Appearance
HTTP Routing
Defining Routes
Routes map HTTP methods and URL paths to handler functions. They are registered on the app instance via register_endpoint.
cpp
using namespace framework;
using namespace framework::clients::http;
app.register_endpoint(
http_verb_t::get, // HTTP method
"/hello", // URL path
handler_function // Your handler
);register_endpoint(method, path, handler, validator, gate, requires_auth)
| Parameter | Type | Required | Description |
|---|---|---|---|
method | http_verb_t | Yes | HTTP verb (get, post, put, delete, patch, etc.) |
path | std::string | Yes | URL path pattern |
handler | http_handler_t | Yes | Function that processes the request and returns a response |
validator | http_validator_t | No | Runs before the handler; returns errors if input is invalid |
gate | http_gate_t | No | Runs before the handler; returns false to reject (403) |
requires_auth | bool | No | If true, JWT authentication is enforced before the handler |
Route Patterns
The path string can contain dynamic segments that are extracted at match time.
Static Paths
cpp
app.register_endpoint(http_verb_t::get, "/hello", handler);
// Matches exactly: GET /helloDynamic (Named) Segments
Use : prefix to mark a path segment as a parameter. Parameters are captured by name and stored in http_params_.path_:
cpp
app.register_endpoint(http_verb_t::get, "/users/:id", handler);
// GET /users/42 → params["id"] = "42"
// GET /users/abc → params["id"] = "abc"
app.register_endpoint(http_verb_t::get, "/posts/:post_id/comments/:comment_id", handler);
// GET /posts/5/comments/12 → params["post_id"] = "5", params["comment_id"] = "12"How Routing Works
The router uses a trie (prefix tree) where each node represents a path segment. When a request arrives, the router walks the trie segment by segment:
- Static nodes match by exact string comparison.
- Parameter nodes (prefixed with
:) act as wildcards — they match any single path component and store its value by name. - The trie structure makes routing O(n) in path depth regardless of how many routes are registered.
Matching Priority
The trie selects the most specific match:
- Static segments beat parameter segments.
/users/mematches the static route over/users/:id. - More static segments beat fewer. A route with more matching static segments takes priority.
- If multiple routes have the same specificity, the one registered first wins.
If no route matches at all, the framework returns a 404 response.
cpp
// Priority example:
app.register_endpoint(http_verb_t::get, "/users/me", me_handler); // static
app.register_endpoint(http_verb_t::get, "/users/:id", user_handler); // parameterized
// GET /users/me → me_handler (static beats param)
// GET /users/42 → user_handler (matches :id)The Route Struct
Internally, each route is stored as a route object:
cpp
struct route {
std::string path_; // URL pattern
http_verb_t http_verb_; // HTTP method
http_handler_t http_handler_; // Response(request) -> response
http_validator_t http_validator_ = nullptr; // Optional input validator
http_gate_t http_gate = nullptr; // Optional authorization gate
bool requires_auth_ = false; // JWT required flag
};Handler Signature
Every handler receives a http_request and must return an http_response_t:
cpp
using http_handler_t = std::function<http_response_t(const http_request&)>;Complete handler example
cpp
app.register_endpoint(
http_verb_t::get,
"/hello",
[](const http_request& req) -> http_response_t {
auto res = helpers::make_base_http_response(req, http_status_t::ok);
auto body = helpers::make_base_http_payload(200, "Hello!");
helpers::finalize_response(res, body);
return res;
}
);Adding Validation
A validator runs before the handler. It returns {is_valid, errors_map}. If is_valid is false, the framework returns a 422 response.
cpp
app.register_endpoint(
http_verb_t::post,
"/users",
create_user_handler,
create_user_validator, // runs before the handler
nullptr, // no gate
false // no auth required
);See Validation for how to write validators.
Adding Authorization Gates
A gate checks authorization before the handler. The built-in gates::is_admin_all checks for admin privileges.
cpp
app.register_endpoint(
http_verb_t::get,
"/admin/stats",
admin_stats_handler,
nullptr,
gates::is_admin_all,
true // requires JWT authentication
);When requires_auth is true, a valid JWT must be present. If the gate returns false, the client receives a 403 response.
Accessing the Router Directly
cpp
auto& router = app.get_router();
router.add_route({"/path", http_verb_t::get, handler});Useful for building dynamic route tables or defining routes outside the main app setup.
Next: Middleware.