DurableRequest
cnerium::DurableRequest is the request type passed to Cnerium durable route handlers.
It wraps the underlying Vix HTTP request and exposes the information needed by durable operations: method, target, path, body, headers, query values, route parameters, JSON parsing, idempotency key access, and request body hashing.
A durable route handler receives it like this:
cnerium.durable_post(
"/orders",
"orders.create",
[](cnerium::DurableRequest &request)
{
const auto body = request.json();
const std::string key = request.idempotency_key_value();
return cnerium::created({
{"ok", true},
{"idempotency_key", key}
});
});DurableRequest does not replace the Vix request model for normal routes. It exists because durable routes need reliability-specific request information.
Use vix::Request in normal Vix routes. Use cnerium::DurableRequest in Cnerium durable routes.
Header
#include <cnerium/cnerium.hpp>or directly:
#include <cnerium/http/DurableRequest.hpp>Most applications should include:
#include <vix.hpp>
#include <cnerium/cnerium.hpp>Namespace
The concrete type is:
cnerium::http::DurableRequestA public alias is available:
cnerium::DurableRequestMost application code should use the public alias:
[](cnerium::DurableRequest &request)
{
// durable handler
}Purpose
DurableRequest exists to give durable handlers a request object that fits the Cnerium execution model.
A normal Vix route receives Vix request and response objects:
app.get("/health", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({
{"ok", true}
});
});A durable Cnerium route receives DurableRequest and returns DurableResponse:
cnerium.durable_post(
"/orders",
"orders.create",
[](cnerium::DurableRequest &request)
{
const auto body = request.json();
return cnerium::created({
{"ok", true}
});
});The durable request still comes from Vix. Cnerium wraps it so durable handlers can access the idempotency key, request hash, and other request data through a focused API.
Construction
Application code normally does not construct DurableRequest directly.
Cnerium creates it internally when a durable route receives a Vix HTTP request.
Conceptually:
Vix receives HTTP request
Vix matches the route
Cnerium wraps the Vix request as DurableRequest
Cnerium performs the durability decision
Cnerium calls the durable handler only when execution is safeThe handler receives the wrapper:
[](cnerium::DurableRequest &request)
{
// use request here
}method
Returns the HTTP method.
std::string method() const;Example:
const std::string method = request.method();For a route registered with durable_post, the method is expected to be POST.
Most durable handlers do not need to check the method because the route registration already determines it.
target
Returns the full request target.
std::string target() const;The target may include the query string.
Example:
const std::string target = request.target();For a request such as:
/orders?source=mobilethe target may include the full value:
/orders?source=mobileUse path() when you only need the path part.
path
Returns the request path.
std::string path() const;Example:
const std::string path = request.path();For most durable handlers, the path is already known from route registration. It can still be useful for logging, diagnostics, or generic handlers.
body
Returns the raw request body.
const std::string &body() const noexcept;Example:
const std::string &raw_body = request.body();Cnerium uses the body internally to compute the request hash used by replay protection.
If the handler expects JSON, use json() or try_json() instead of manually parsing the raw body.
header
Returns the value of an HTTP header.
std::string header(std::string_view name) const;Example:
const std::string content_type = request.header("Content-Type");If the header is missing, the method returns an empty string.
Use this for request metadata that is relevant to your durable operation.
has_header
Returns whether a header exists.
bool has_header(std::string_view name) const;Example:
if (request.has_header("Content-Type"))
{
const std::string content_type =
request.header("Content-Type");
}Durable routes require Idempotency-Key, but application code usually does not need to manually check it. Cnerium validates the key before the handler executes.
idempotency_key
Returns the Idempotency-Key header as a value object.
cnerium::reliability::IdempotencyKey
idempotency_key() const;Example:
const auto key = request.idempotency_key();
if (key.is_valid())
{
const std::string value =
key.value();
}Most application handlers can use idempotency_key_value() when they only need the raw string.
idempotency_key_value
Returns the raw Idempotency-Key header value.
std::string idempotency_key_value() const;Example:
const std::string order_id = "ord_" + request.idempotency_key_value();This is useful when the application wants to include the operation key in a generated demo id, an audit log, or a call to another idempotent system.
In production, the final domain id often comes from a database or external service. The idempotency key should still remain the retry identity for the operation.
request_hash
Computes the stable request body hash used by Cnerium.
cnerium::reliability::RequestHash
request_hash() const;Example:
const auto hash = request.request_hash();Most application handlers do not need to use the request hash directly. Cnerium uses it internally to detect whether a repeated Idempotency-Key is being used with the same body or a different body.
Use it for diagnostics only when necessary.
json
Parses the request body as JSON.
cnerium::support::Json json() const;Example:
const auto body = request.json();
const std::string product_id = cnerium::support::string_or(body, "product_id", "");
const int quantity = cnerium::support::int_or(body, "quantity", 0);If the body is not valid JSON, this method may throw according to the JSON parser behavior used by the current Cnerium and Vix JSON integration.
Use try_json() when the handler should avoid exceptions.
try_json
Parses the request body as JSON without throwing.
std::optional<cnerium::support::Json>
try_json() const noexcept;Example:
const auto body = request.try_json();
if (!body.has_value())
{
return cnerium::DurableResponse::bad_request(
"Request body must be valid JSON");
}
const std::string product_id = cnerium::support::string_or(*body, "product_id", "");Use this when the route should return a clean validation response for malformed JSON.
param
Returns a route parameter value.
std::string param(std::string_view name) const;Example:
const std::string order_id = request.param("id");If the parameter is missing, the method returns an empty string.
Use route parameters for durable routes that operate on a named resource or command path.
query
Returns a query parameter value.
std::string query(std::string_view name) const;Example:
const std::string source = request.query("source");If the query parameter is missing, the method returns an empty string.
For durable routes, be careful with query parameters. Cnerium’s core replay protection is based on the request body hash and idempotency key. If query parameters affect the meaning of a critical operation, keep the route design stable and make sure clients retry with the same full request.
native
Returns the wrapped Vix HTTP request.
const vix::http::Request &native() const noexcept;Example:
const auto &vix_request = request.native();Most application code should not need this. It is available for integration code that needs access to lower-level Vix request data not exposed directly by DurableRequest.
Use it carefully. Durable handlers should usually stay inside the Cnerium request API.
Complete example
#include <vix.hpp>
#include <cnerium/cnerium.hpp>
#include <string>
int main()
{
vix::App app;
auto cnerium = cnerium::attach(app);
app.get("/health", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({
{"ok", true},
{"service", "orders"}
});
});
cnerium.durable_post(
"/orders",
"orders.create",
[](cnerium::DurableRequest &request)
{
const auto body = request.try_json();
if (!body.has_value())
{
return cnerium::DurableResponse::bad_request(
"Request body must be valid JSON");
}
const std::string product_id = cnerium::support::string_or(*body, "product_id", "");
const int quantity = cnerium::support::int_or(*body, "quantity", 0);
if (product_id.empty())
{
return cnerium::DurableResponse::bad_request(
"Missing required field: product_id");
}
if (quantity <= 0)
{
return cnerium::DurableResponse::bad_request(
"Field quantity must be greater than zero");
}
const std::string order_id = "ord_" + request.idempotency_key_value();
return cnerium::created({
{"ok", true},
{"order_id", order_id},
{"product_id", product_id},
{"quantity", quantity}
});
});
if (!cnerium.start())
{
return 1;
}
app.run();
return 0;
}This route uses try_json() to return a clean error for invalid JSON and uses idempotency_key_value() to produce a deterministic example id.
Relationship with replay protection
DurableRequest provides the values needed by replay protection, but application handlers do not normally run the replay decision themselves.
Before the handler executes, Cnerium has already checked:
operation name
Idempotency-Key
request body hashIf the request is a safe replay, the handler is not called. If the request is an unsafe reuse of the same key with a different body, the handler is not called. If the key is missing, the handler is not called.
The handler receives DurableRequest only when Cnerium has decided that the operation should execute.
Common mistakes
Do not use DurableRequest in normal Vix routes. Normal routes should use Vix request and response types.
Do not manually implement idempotency inside every handler. Cnerium performs the idempotency and replay-protection decision before the handler runs.
Do not rely on query parameters to change the meaning of a durable operation unless the route is designed carefully and the client retries the exact same request.
Do not perform critical side effects before the durable route receives the request. Cnerium can only protect side effects that occur inside the durable execution path.
Do not assume json() always returns a valid body. Use try_json() when the route needs graceful malformed JSON handling.
Summary
cnerium::DurableRequest is the request wrapper used by Cnerium durable route handlers.
It gives handlers access to request data while exposing durable-route helpers such as idempotency_key_value(), request_hash(), json(), and try_json(). The object wraps a Vix request, but it belongs to the Cnerium durable route execution model.
Use it only inside durable handlers registered with cnerium.durable_post.