Ichor provides an Expressjs-inspired abstraction for setting up an Http(s) server.
The Boost HttpHostService implementation requires a logger, the AsioContextService and the HttpHostService itself to be set up:
#include <ichor/services/network/boost/HttpHostService.h>
#include <ichor/services/network/boost/AsioContextService.h>
#include <ichor/services/logging/NullLogger.h>
int main(int argc, char *argv[]) {
auto queue = std::make_unique<PriorityQueue>();
auto &dm = queue->createManager();
dm.createServiceManager<LoggerFactory<NullLogger>, ILoggerFactory>();
dm.createServiceManager<AsioContextService, IAsioContextService>(Properties{{"Threads", Ichor::make_any<uint64_t>(2)}});
dm.createServiceManager<HttpHostService, IHttpHostService>(Properties{{"Address", Ichor::make_any<std::string>("localhost")}, {"Port", Ichor::make_any<uint16_t>(static_cast<uint16_t>(8001))}});
queue->start(CaptureSigInt);
return 0;
}
#include <ichor/services/network/http/IHttpHostService.h>
class UsingHttpService final {
UsingHttpService(IHttpHostService *host) {
_routeRegistrations.emplace_back(host->addRoute(HttpMethod::post, "/test", [this](HttpRequest &req) -> AsyncGenerator<HttpResponse> {
co_return HttpResponse{HttpStatus::ok, "application/text", "<html><body>This is my basic webpage</body></html>", {}};
}));
}
std::vector<std::unique_ptr<HttpRouteRegistration>> _routeRegistrations{};
};
To add routes that capture parts of the URL, Ichor provides a regex route matcher that supports capture groups:
#include <ichor/services/network/http/IHttpHostService.h>
class UsingHttpService final {
UsingHttpService(IHttpHostService *host) {
_routeRegistrations.emplace_back(svc.addRoute(HttpMethod::get, std::make_unique<RegexRouteMatch<R"(\/user\/(\d{1,2})\?*(.*))">>(), [this](HttpRequest &req) -> AsyncGenerator<HttpResponse> {
std::string user_id = req.regex_params[0];
if(req.regex_params.size() > 1) {
std::string query_params = req.regex_params[1]; // e.g. param1=one¶m2=two, parsing string is left to the user for now, though Ichor does provide a string_view split function in stl/StringUtils.h
}
co_return HttpResponse{HttpStatus::ok, "text/plain", {}, {}};
}));
}
std::vector<std::unique_ptr<HttpRouteRegistration>> _routeRegistrations{};
};
The regex_params
is a vector with the capture groups counted from left to right.
If you want to add custom logic on matching routes, because maybe you want to use a different regex library than CTRE, implement the interface to RouteMatcher:
struct CustomRouteMatcher final : public RouteMatcher {
~CustomRouteMatcher() noexcept final = default;
[[nodiscard]] bool matches(std::string_view route) noexcept final {
if(route == "/test") {
return true;
}
return false;
}
// these get moved into HttpRequest's regex_params
[[nodiscard]] std::vector<std::string> route_params() noexcept final {
return {};
}
};
And use that with the route registration:
_routeRegistrations.emplace_back(svc.addRoute(HttpMethod::get, std::make_unique<CustomRouteMatcher>(), [this](HttpRequest &req) -> AsyncGenerator<HttpResponse> {
co_return HttpResponse{HttpStatus::ok, "text/plain", {}, {}};
}));