Skip to content

Middleware

The framework supports two types of middleware: gates (authorization) and validators (input validation). Both run before your route handler and can reject the request early.


Gates — Authorization Checks

A gate is a function that returns true (allow) or false (reject). When a gate returns false, the framework responds with HTTP 403.

Built-in Gate: is_admin_all

The built-in admin gate is in framework::clients::http::gates:

cpp
using namespace framework;
using namespace framework::clients::http;
using namespace framework::clients::http::gates;

app.register_endpoint(
    http_verb_t::get,
    "/admin/stats",
    handler,
    nullptr,                // no validator
    is_admin_all,           // gate
    true                    // requires auth (JWT)
);

Custom Gate

Access the configuration from the state and check JWT claims:

cpp
app.register_endpoint(
    http_verb_t::get,
    "/admin/users",
    handler,
    nullptr,
    [](const http_request& req) -> bool {
        auto& config = req.state_->get_configuration();
        auto& jwt = req.http_connection_.get_jwt();
        if (!jwt.is_valid(config)) return false;
        return jwt.has_claims("admin", "users");
    },
    true
);

Gate signature:

cpp
using http_gate_t = std::function<bool(const http_request&)>;
// Return true to allow, false to reject with 403.

Validators — Input Validation

A validator runs before the handler and checks the request body. If it returns {false, errors}, the framework responds with HTTP 422.

cpp
using namespace framework;
using namespace framework::clients::http;

auto user_validator = [](const http_request& req)
    -> std::pair<bool, std::unordered_map<std::string, std::vector<std::string>>> {
    if (!req.body_.has_value()) {
        return {false, {{"body", {"Request body is required"}}}};
    }
    // Validate fields...
    return {true, {}};
};

app.register_endpoint(
    http_verb_t::post,
    "/users",
    handler,
    user_validator
);

Validator signature:

cpp
using http_validator_t = std::function<
    std::pair<bool, std::unordered_map<std::string, std::vector<std::string>>>(
        const http_request&)>;
// Return {true, {}} for valid.
// Return {false, {"field": {"message"}}} for invalid.

CORS Configuration

Cross-Origin Resource Sharing is configured through the configuration object.

cpp
using namespace framework;

configuration config;
config.cors_.enabled_.store(true);
config.cors_.origin_.store(std::make_shared<const std::string>("*"));
config.cors_.headers_.store(std::make_shared<const std::string>("Content-Type, Authorization"));

framework::app app(config);
Config FieldDefaultDescription
cors_.enabled_trueEnable or disable CORS headers.
cors_.origin_"*"Allowed origin(s).
cors_.headers_"Content-Type, Authorization"Allowed headers.

Middleware Pipeline Order

When a request arrives, the processing pipeline runs in this exact order:

  1. JWT verification — If requires_auth is true, the JWT is verified before anything else.
  2. Gate — If set, runs and may return 403.
  3. Validator — If set, runs and may return 422.
  4. Handler — Executes and returns the response.

After the handler returns, CORS headers are injected into the response before it is sent to the client.

If any step rejects the request, the pipeline stops and the error response is sent immediately.