Skip to content

Commit

Permalink
Implement first version of config service
Browse files Browse the repository at this point in the history
  • Loading branch information
Joachim Rosskopf committed Dec 30, 2024
1 parent 79729a2 commit eb3ccb2
Show file tree
Hide file tree
Showing 10 changed files with 563 additions and 8 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ add_library(flapi-lib STATIC
src/auth_middleware.cpp
src/cache_manager.cpp
src/config_manager.cpp
src/config_service.cpp
src/database_manager.cpp
src/heartbeat_worker.cpp
src/open_api_doc_generator.cpp
Expand Down
5 changes: 0 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,6 @@ run-release: release
@echo "Running release version..."
@$(RELEASE_DIR)/flapi --config examples/flapi.yaml --log-level info

# Run release tests
run-release-tests: release
@echo "Running release tests..."
@$(RELEASE_DIR)/test/cpp/flapi_tests

# Run integration tests
run-integration-tests: debug
@echo "Running integration tests..."
Expand Down
2 changes: 1 addition & 1 deletion src/config_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ std::chrono::seconds CacheConfig::getRefreshTimeInSeconds() const
std::istringstream iss(refreshTime);
iss >> value >> unit;

if (iss.fail() || value < 0) {
if (iss.fail()) {
throw std::runtime_error("Invalid refresh time format: " + refreshTime);
}

Expand Down
267 changes: 267 additions & 0 deletions src/config_service.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
#include <filesystem>
#include <fstream>
#include <sstream>

#include "config_service.hpp"

namespace flapi {

ConfigService::ConfigService(std::shared_ptr<ConfigManager> config_manager,
std::shared_ptr<RequestHandler> request_handler)
: config_manager(config_manager), request_handler(request_handler) {}

void ConfigService::registerRoutes(FlapiApp& app) {
CROW_LOG_INFO << "Registering config routes";

// Project configuration routes
CROW_ROUTE(app, "/api/v1/_config/project")
.methods("GET"_method, "PUT"_method)
([this](const crow::request& req) {
if (req.method == crow::HTTPMethod::Get)
return getProjectConfig(req);
else
return updateProjectConfig(req);
});

// Endpoints configuration routes
CROW_ROUTE(app, "/api/v1/_config/endpoints")
.methods("GET"_method, "POST"_method)
([this](const crow::request& req) {
if (req.method == crow::HTTPMethod::Get)
return listEndpoints(req);
else
return createEndpoint(req);
});

CROW_ROUTE(app, "/api/v1/_config/endpoints/<string>")
.methods("GET"_method, "PUT"_method, "DELETE"_method)
([this](const crow::request& req, const std::string& path) {
switch (req.method) {
case crow::HTTPMethod::Get:
return getEndpointConfig(req, path);
case crow::HTTPMethod::Put:
return updateEndpointConfig(req, path);
case crow::HTTPMethod::Delete:
return deleteEndpoint(req, path);
default:
return crow::response(405);
}
});

// Template routes
CROW_ROUTE(app, "/api/v1/_config/endpoints/<string>/template")
.methods("GET"_method, "PUT"_method)
([this](const crow::request& req, const std::string& path) {
if (req.method == crow::HTTPMethod::Get)
return getEndpointTemplate(req, path);
else
return updateEndpointTemplate(req, path);
});

CROW_ROUTE(app, "/api/v1/_config/endpoints/<string>/template/expand")
.methods("POST"_method)
([this](const crow::request& req, const std::string& path) {
return expandTemplate(req, path);
});

CROW_ROUTE(app, "/api/v1/_config/endpoints/<string>/template/test")
.methods("POST"_method)
([this](const crow::request& req, const std::string& path) {
return testTemplate(req, path);
});

// Cache routes
CROW_ROUTE(app, "/api/v1/_config/endpoints/<string>/cache")
.methods("GET"_method, "PUT"_method)
([this](const crow::request& req, const std::string& path) {
if (req.method == crow::HTTPMethod::Get)
return getCacheConfig(req, path);
else
return updateCacheConfig(req, path);
});

CROW_ROUTE(app, "/api/v1/_config/endpoints/<string>/cache/template")
.methods("GET"_method, "PUT"_method)
([this](const crow::request& req, const std::string& path) {
if (req.method == crow::HTTPMethod::Get)
return getCacheTemplate(req, path);
else
return updateCacheTemplate(req, path);
});

CROW_ROUTE(app, "/api/v1/_config/endpoints/<string>/cache/refresh")
.methods("POST"_method)
([this](const crow::request& req, const std::string& path) {
return refreshCache(req, path);
});

// Schema routes
CROW_ROUTE(app, "/api/v1/_config/schema")
.methods("GET"_method)
([this](const crow::request& req) {
return getSchema(req);
});

CROW_ROUTE(app, "/api/v1/_config/schema/refresh")
.methods("POST"_method)
([this](const crow::request& req) {
return refreshSchema(req);
});
}

crow::response ConfigService::getProjectConfig(const crow::request& req) {
try {
if (!config_manager) {
return crow::response(500, "Internal server error: Configuration manager is not initialized");
}
auto config = config_manager->getFlapiConfig();
return crow::response(200, config);
} catch (const std::exception& e) {
return crow::response(500, std::string("Internal server error: ") + e.what());
}
}

crow::response ConfigService::updateProjectConfig(const crow::request& req) {
try {
auto json = crow::json::load(req.body);
if (!json)
return crow::response(400, "Invalid JSON");

// TODO: Implement project config update logic
return crow::response(501, "Not implemented");
} catch (const std::exception& e) {
return crow::response(500, std::string("Internal server error: ") + e.what());
}
}

crow::response ConfigService::listEndpoints(const crow::request& req) {
try {
auto endpoints = config_manager->getEndpointsConfig();
return crow::response(200, endpoints);
} catch (const std::exception& e) {
return crow::response(500, std::string("Internal server error: ") + e.what());
}
}

crow::response ConfigService::createEndpoint(const crow::request& req) {
try {
auto json = crow::json::load(req.body);
if (!json)
return crow::response(400, "Invalid JSON");

auto endpoint = jsonToEndpointConfig(json);
config_manager->addEndpoint(endpoint);

return crow::response(201);
} catch (const std::exception& e) {
return crow::response(500, std::string("Internal server error: ") + e.what());
}
}

crow::response ConfigService::getEndpointConfig(const crow::request& req, const std::string& path) {
try {
const auto* endpoint = config_manager->getEndpointForPath(path);
if (!endpoint)
return crow::response(404, "Endpoint not found");

return crow::response(200, endpointConfigToJson(*endpoint));
} catch (const std::exception& e) {
return crow::response(500, std::string("Internal server error: ") + e.what());
}
}

// Helper methods for converting between JSON and EndpointConfig
crow::json::wvalue ConfigService::endpointConfigToJson(const EndpointConfig& config) {
crow::json::wvalue json;
json["url-path"] = config.urlPath;
json["template-source"] = config.templateSource;

// Add request fields
std::vector<crow::json::wvalue> requestFields;
for (const auto& field : config.requestFields) {
crow::json::wvalue fieldJson;
fieldJson["field-name"] = field.fieldName;
fieldJson["field-in"] = field.fieldIn;
fieldJson["description"] = field.description;
fieldJson["required"] = field.required;
requestFields.push_back(std::move(fieldJson));
}
json["request"] = std::move(requestFields);

return json;
}

EndpointConfig ConfigService::jsonToEndpointConfig(const crow::json::rvalue& json) {
EndpointConfig config;
config.urlPath = json["url-path"].s();
config.templateSource = json["template-source"].s();

// Parse request fields
if (json.has("request")) {
for (const auto& field : json["request"]) {
RequestFieldConfig fieldConfig;
fieldConfig.fieldName = field["field-name"].s();
fieldConfig.fieldIn = field["field-in"].s();
fieldConfig.description = field["description"].s();
fieldConfig.required = field["required"].b();
config.requestFields.push_back(fieldConfig);
}
}

return config;
}

// Implement remaining endpoint handlers...
crow::response ConfigService::updateEndpointConfig(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::deleteEndpoint(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::getEndpointTemplate(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::updateEndpointTemplate(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::expandTemplate(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::testTemplate(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::getCacheConfig(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::updateCacheConfig(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::getCacheTemplate(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::updateCacheTemplate(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::refreshCache(const crow::request& req, const std::string& path) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::getSchema(const crow::request& req) {
return crow::response(501, "Not implemented");
}

crow::response ConfigService::refreshSchema(const crow::request& req) {
return crow::response(501, "Not implemented");
}

} // namespace flapi
4 changes: 3 additions & 1 deletion src/include/api_server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

namespace flapi {

using FlapiApp = crow::App<crow::CORSHandler, RateLimitMiddleware, AuthMiddleware>;

class HeartbeatWorker; // forward declaration

class APIServer
Expand All @@ -37,7 +39,7 @@ class APIServer
void handleDynamicRequest(const crow::request& req, crow::response& res);
crow::response generateOpenAPIDoc();

crow::App<crow::CORSHandler, RateLimitMiddleware, AuthMiddleware> app;
FlapiApp app;
std::shared_ptr<ConfigManager> configManager;
std::shared_ptr<DatabaseManager> dbManager;
std::shared_ptr<OpenAPIDocGenerator> openAPIDocGenerator;
Expand Down
1 change: 0 additions & 1 deletion src/include/config_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ class ConfigManager {
void printConfig() const;
static void printYamlNode(const YAML::Node& node, int indent = 0);


protected:
std::filesystem::path config_file;
YAML::Node config;
Expand Down
56 changes: 56 additions & 0 deletions src/include/config_service.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

#include <crow.h>
#include "crow/middlewares/cors.h"
#include <memory>

#include "api_server.hpp"
#include "config_manager.hpp"
#include "request_handler.hpp"

namespace flapi {

class ConfigService {
public:
ConfigService(std::shared_ptr<ConfigManager> config_manager,
std::shared_ptr<RequestHandler> request_handler);

void registerRoutes(FlapiApp& app);

std::shared_ptr<ConfigManager> config_manager;
std::shared_ptr<RequestHandler> request_handler;

// Route handlers
crow::response getProjectConfig(const crow::request& req);
crow::response updateProjectConfig(const crow::request& req);

crow::response listEndpoints(const crow::request& req);
crow::response createEndpoint(const crow::request& req);

crow::response getEndpointConfig(const crow::request& req, const std::string& path);
crow::response updateEndpointConfig(const crow::request& req, const std::string& path);
crow::response deleteEndpoint(const crow::request& req, const std::string& path);

crow::response getEndpointTemplate(const crow::request& req, const std::string& path);
crow::response updateEndpointTemplate(const crow::request& req, const std::string& path);

crow::response expandTemplate(const crow::request& req, const std::string& path);
crow::response testTemplate(const crow::request& req, const std::string& path);

crow::response getCacheConfig(const crow::request& req, const std::string& path);
crow::response updateCacheConfig(const crow::request& req, const std::string& path);

crow::response getCacheTemplate(const crow::request& req, const std::string& path);
crow::response updateCacheTemplate(const crow::request& req, const std::string& path);

crow::response refreshCache(const crow::request& req, const std::string& path);

crow::response getSchema(const crow::request& req);
crow::response refreshSchema(const crow::request& req);

// Helper methods
crow::json::wvalue endpointConfigToJson(const EndpointConfig& config);
EndpointConfig jsonToEndpointConfig(const crow::json::rvalue& json);
};

} // namespace flapi
1 change: 1 addition & 0 deletions test/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ add_executable(flapi_tests
sql_template_processor_test.cpp
auth_middleware_test.cpp
database_manager_test.cpp
config_service_test.cpp
)

target_include_directories(flapi_tests PRIVATE
Expand Down
Loading

0 comments on commit eb3ccb2

Please sign in to comment.