134 lines
3.8 KiB
C++
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);
|
|
}
|