Files
backend/controllers/ApiController.cc
T
2026-06-02 20:40:45 +02:00

134 lines
3.8 KiB
C++

#include "ApiController.h"
#include <drogon/drogon.h>
#include <drogon/orm/Exception.h>
#include <json/json.h>
#include <filesystem>
#include <fstream>
#include <memory>
#include <sstream>
using drogon::HttpResponse;
using drogon::HttpResponsePtr;
using drogon::k503ServiceUnavailable;
namespace
{
HttpResponsePtr jsonResponse(Json::Value body,
drogon::HttpStatusCode status = drogon::k200OK)
{
auto response = HttpResponse::newHttpJsonResponse(std::move(body));
response->setStatusCode(status);
return response;
}
Json::Value mysqlReadyBody(bool ready)
{
Json::Value body;
body["status"] = ready ? "ready" : "not_ready";
body["dependencies"]["mysql"] = ready;
return body;
}
std::string openApiSpecPath()
{
const auto &config = drogon::app().getCustomConfig()["openapi"];
return config.get("spec_path", "build/openapi/visione.openapi.json").asString();
}
}
void ApiController::health(
const drogon::HttpRequestPtr &,
std::function<void(const HttpResponsePtr &)> &&callback)
{
Json::Value body;
body["status"] = "ok";
body["service"] = "visione-backend";
callback(jsonResponse(std::move(body)));
}
void ApiController::ready(
const drogon::HttpRequestPtr &,
std::function<void(const HttpResponsePtr &)> &&callback)
{
auto responseCallback = std::make_shared<
std::function<void(const HttpResponsePtr &)>>(std::move(callback));
try
{
auto dbClient = drogon::app().getDbClient();
dbClient->execSqlAsync(
"SELECT 1",
[responseCallback](const drogon::orm::Result &) {
(*responseCallback)(jsonResponse(mysqlReadyBody(true)));
},
[responseCallback](const drogon::orm::DrogonDbException &error) {
auto body = mysqlReadyBody(false);
body["errors"]["mysql"] = error.base().what();
(*responseCallback)(
jsonResponse(std::move(body), k503ServiceUnavailable));
});
}
catch (const std::exception &error)
{
auto body = mysqlReadyBody(false);
body["errors"]["mysql"] = error.what();
(*responseCallback)(
jsonResponse(std::move(body), k503ServiceUnavailable));
}
}
void ApiController::openApi(
const drogon::HttpRequestPtr &,
std::function<void(const HttpResponsePtr &)> &&callback)
{
const auto path = openApiSpecPath();
std::ifstream file(path, std::ios::binary);
if (!file)
{
Json::Value body;
body["error"] = "openapi_spec_not_generated";
body["message"] = "Run cmake --build build or the openapi target.";
body["path"] = path;
callback(jsonResponse(std::move(body), drogon::k404NotFound));
return;
}
std::ostringstream buffer;
buffer << file.rdbuf();
auto response = HttpResponse::newHttpResponse();
response->setStatusCode(drogon::k200OK);
response->setContentTypeCode(drogon::CT_APPLICATION_JSON);
response->setBody(buffer.str());
callback(response);
}
void ApiController::docs(
const drogon::HttpRequestPtr &,
std::function<void(const HttpResponsePtr &)> &&callback)
{
static const std::string html = R"(<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Visione API Docs</title>
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css">
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
<script>
window.ui = SwaggerUIBundle({ url: "/api/v1/openapi.json", dom_id: "#swagger-ui" });
</script>
</body>
</html>)";
auto response = HttpResponse::newHttpResponse();
response->setStatusCode(drogon::k200OK);
response->setContentTypeCode(drogon::CT_TEXT_HTML);
response->setBody(html);
callback(response);
}