| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
A small C++17 HTTP service sample.
The service now exposes basic observability endpoints by default:
You also need these libraries discoverable by CMake via find_package(... CONFIG REQUIRED): - nlohmann-json - spdlog - fmt - cxxopts
Install the dependencies using your system package manager (or build/install them yourself) so that CMake can find their Config packages.
Example (Ubuntu/Debian):
sudo apt update
sudo apt install -y \
nlohmann-json3-dev \
libspdlog-dev \
libfmt-dev \
libcxxopts-devIf your distro does not provide cxxopts as a CMake package, build and install it from source, then set CMAKE_PREFIX_PATH to the install prefix when configuring.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -jNote: the CMake build adds a POST_BUILD step that copies config.json next to the built executable.
This project uses find_package(... CONFIG REQUIRED). On Windows, the simplest way to satisfy those dependencies is to use vcpkg in toolchain mode.
From a Developer PowerShell:
cd $env:VCPKG_ROOT
./vcpkg install nlohmann-json spdlog fmt cxxoptsIf you want a specific architecture, add a triplet, for example:
./vcpkg install nlohmann-json spdlog fmt cxxopts --triplet x64-windowsFrom the repository root:
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake"
cmake --build build --config ReleaseNote: the build copies config.json next to the built executable.
Linux/macOS:
cd build
./app_servicesWindows (example for CMake multi-config generators):
.\build\Release\app_services.exeYou should see logs like:
The service loads config.json from:
If you start the binary from a different directory (not the one containing config.json), config loading will fail.
Supported fields:
Example config.json:
{
"host": "0.0.0.0",
"port": 8080,
"threads": 6
}On startup, the app creates:
And writes a rotating log file:
If you don’t set data_dir on Linux/macOS, logs will be under:
Routing is wrapped by ApiRouter (see src/api_router.h). Register endpoints inside register_handlers(ApiRouter& api) (see src/handlers.cpp).
A handler has the signature:
using Handler = std::function<void(const httplib::Request&, httplib::Response&)>;Example endpoint GET /hello (already present):
api.get("/hello", [](const httplib::Request& req, httplib::Response& res) {
nlohmann::json j;
j["message"] = "Hello, World!";
res.status = 200;
res.set_content(j.dump(), "application/json");
});Available route registration helpers:
Quick notes for handlers:
To group endpoints under a prefix (e.g. /api/v1), use group(prefix, define_routes):
api.group("/api/v1", [](ApiRouter& r) {
r.get("/ping", [](const httplib::Request&, httplib::Response& res) {
res.status = 200;
res.set_content("pong", "text/plain; charset=utf-8");
});
});
// -> GET /api/v1/pingMiddleware has the signature:
using Next = std::function<void()>;
using Middleware = std::function<void(const httplib::Request&, httplib::Response&, Next)>;There are two kinds:
Middleware runs as a chain. If you want the request to continue to the route handler (or the next middleware), you must call next(). If you set a response and don’t call next(), the request stops there (commonly used for auth/deny).
api.use([](const httplib::Request& req, httplib::Response& res, ApiRouter::Next next) {
const auto start = std::chrono::steady_clock::now();
next();
const auto end = std::chrono::steady_clock::now();
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
spdlog::info("{} {} took {}ms status={}", req.method, req.path, ms, res.status);
});api.use([](const httplib::Request& req, httplib::Response& res, ApiRouter::Next next) {
auto it = req.headers.find("x-api-key");
if (it == req.headers.end() || it->second != "secret") {
res.status = 401;
res.set_content("unauthorized", "text/plain; charset=utf-8");
return; // no next() => stop
}
next();
});api.use_after([](const httplib::Request&, httplib::Response& res, ApiRouter::Next next) {
next();
res.set_header("x-service", "app_services");
});For a real example used in this repo, see the observability middleware in src/observability.cpp.
Returns plain text:
ok
Quick test:
curl -s http://127.0.0.1:8080/healthzReturns a small JSON payload (counters are process-wide):
{"requests_total":123,"requests_in_flight":0}Quick test:
curl -s http://127.0.0.1:8080/statusPrometheus text format endpoint. Currently disabled in handler registration.
Returns tracing/correlation headers (and echoes them in the body). Currently disabled in handler registration.
Unknown routes return:
{"error":"not found"}Supported options:
Note: Service recovery (automatic restarts on failure) is configured by the installer script. Control Manager defaults baked into the app.
| Back | FazBrowse Home | New Git URL |