Request
This page shows how to use vix::Request in Vix Core.
Use it when you want to read the HTTP method, path, query parameters, route parameters, headers, body, JSON data, or request-scoped state.
Public header
#include <vix.hpp>You can also include the request header directly:
#include <vix/http/Request.hpp>What Request provides
vix::Request represents an incoming HTTP request.
It gives access to:
- HTTP method
- full target
- path without query string
- raw query string
- parsed query parameters
- route parameters
- request headers
- request body
- parsed JSON body
- request-scoped state
Most handlers receive a request by reference.
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.text("Hello");
});Basic usage
#include <vix.hpp>
int main()
{
vix::App app;
app.get("/debug", [](vix::Request &req, vix::Response &res)
{
res.json({
{"method", req.method()},
{"path", req.path()},
{"target", req.target()}
});
});
app.run(8080);
return 0;
}Request:
GET /debug?page=1Example response:
{
"method": "GET",
"path": "/debug",
"target": "/debug?page=1"
}HTTP method
Use method() to read the request method.
app.get("/method", [](vix::Request &req, vix::Response &res)
{
res.json({
{"method", req.method()}
});
});Example:
GET
POST
PUT
PATCH
DELETE
HEAD
OPTIONSTarget
Use target() to read the full request target.
The target includes the path and query string.
app.get("/debug", [](vix::Request &req, vix::Response &res)
{
res.json({
{"target", req.target()}
});
});Request:
GET /debug?page=2Example response:
{
"target": "/debug?page=2"
}Path
Use path() to read the path without the query string.
app.get("/debug", [](vix::Request &req, vix::Response &res)
{
res.json({
{"path", req.path()}
});
});Request:
GET /debug?page=2Example response:
{
"path": "/debug"
}Raw query string
Use query_string() to read the raw query string without ?.
app.get("/search", [](vix::Request &req, vix::Response &res)
{
res.json({
{"query_string", req.query_string()}
});
});Request:
GET /search?q=vix&page=2Example response:
{
"query_string": "q=vix&page=2"
}Query parameters
Use query_value(...) to read one query parameter.
app.get("/search", [](vix::Request &req, vix::Response &res)
{
const std::string q = req.query_value("q", "");
const std::string page = req.query_value("page", "1");
res.json({
{"q", q},
{"page", page}
});
});Request:
GET /search?q=vix&page=2Example response:
{
"q": "vix",
"page": "2"
}Query fallback
The second argument to query_value(...) is the fallback value.
const std::string page = req.query_value("page", "1");If the query parameter is missing, the fallback is returned.
GET /search?q=vixResult:
page = 1Check query parameter
Use has_query(...).
app.get("/search", [](vix::Request &req, vix::Response &res)
{
if (!req.has_query("q"))
{
res.status(400).json({
{"error", "missing query parameter q"}
});
return;
}
res.json({
{"q", req.query_value("q")}
});
});Read all query parameters
Use query() to access the parsed query map.
app.get("/search", [](vix::Request &req, vix::Response &res)
{
const auto &query = req.query();
res.json({
{"count", query.size()}
});
});Route parameters
Use param(...) to read a route parameter.
app.get("/users/{id}", [](vix::Request &req, vix::Response &res)
{
res.json({
{"id", req.param("id")}
});
});Request:
GET /users/42Example response:
{
"id": "42"
}Route parameter fallback
Use the second argument to provide a fallback.
const std::string id = req.param("id", "unknown");If the parameter does not exist, the fallback is returned.
Check route parameter
Use has_param(...).
app.get("/users/{id}", [](vix::Request &req, vix::Response &res)
{
if (!req.has_param("id"))
{
res.status(400).json({
{"error", "missing id"}
});
return;
}
res.json({
{"id", req.param("id")}
});
});Read all route parameters
Use params().
app.get("/users/{user_id}/posts/{post_id}", [](vix::Request &req, vix::Response &res)
{
const auto ¶ms = req.params();
res.json({
{"count", params.size()},
{"user_id", req.param("user_id")},
{"post_id", req.param("post_id")}
});
});Request:
GET /users/7/posts/42Example response:
{
"count": 2,
"user_id": "7",
"post_id": "42"
}Headers
Use header(...) to read a header value.
app.get("/agent", [](vix::Request &req, vix::Response &res)
{
res.json({
{"user_agent", req.header("User-Agent")}
});
});If the header is missing, an empty string is returned.
Check header
Use has_header(...).
app.get("/auth", [](vix::Request &req, vix::Response &res)
{
if (!req.has_header("Authorization"))
{
res.status(401).json({
{"error", "missing authorization header"}
});
return;
}
res.json({
{"authorized", true}
});
});Read all headers
Use headers().
app.get("/headers", [](vix::Request &req, vix::Response &res)
{
const auto &headers = req.headers();
res.json({
{"count", headers.size()}
});
});Body
Use body() to read the raw request body.
app.post("/echo", [](vix::Request &req, vix::Response &res)
{
res.text(req.body());
});Request body:
hello from VixResponse:
hello from VixJSON body
Use json() to parse the body as JSON.
app.post("/json", [](vix::Request &req, vix::Response &res)
{
const auto &body = req.json();
res.json({
{"received", body}
});
});Request body:
{
"name": "Ada"
}Example response:
{
"received": {
"name": "Ada"
}
}Convert JSON body
Use json_as<T>() to convert the parsed JSON body to a type when supported.
auto value = req.json_as<MyType>();Example shape:
app.post("/users", [](vix::Request &req, vix::Response &res)
{
auto user = req.json_as<User>();
res.status(201).json({
{"created", true}
});
});The conversion depends on the JSON type support available for T.
Request state
RequestState is request-scoped storage.
Use it when middleware needs to pass data to handlers.
struct CurrentUser
{
std::string id;
};Middleware can store a value.
app.use([](vix::Request &req, vix::Response &res, vix::App::Next next)
{
(void)res;
req.state().set(CurrentUser{"42"});
next();
});A handler can read it later.
app.get("/me", [](vix::Request &req, vix::Response &res)
{
const auto &user = req.state().get<CurrentUser>();
res.json({
{"id", user.id}
});
});Check request state
Use has_state_type<T>().
if (req.has_state_type<CurrentUser>())
{
const auto &user = req.state().get<CurrentUser>();
}Optional request state
Use try_get<T>() when a value may be missing.
app.get("/me", [](vix::Request &req, vix::Response &res)
{
auto *user = req.state().try_get<CurrentUser>();
if (!user)
{
res.status(401).json({
{"error", "unauthorized"}
});
return;
}
res.json({
{"id", user->id}
});
});Store request state in middleware
#include <vix.hpp>
#include <string>
struct CurrentUser
{
std::string id;
};
int main()
{
vix::App app;
app.use("/api/private", [](vix::Request &req, vix::Response &res, vix::App::Next next)
{
const std::string token = req.header("Authorization");
if (token.empty())
{
res.status(401).json({
{"error", "missing authorization header"}
});
return;
}
req.state().set(CurrentUser{"42"});
next();
});
app.get("/api/private/me", [](vix::Request &req, vix::Response &res)
{
const auto &user = req.state().get<CurrentUser>();
res.json({
{"id", user.id}
});
});
app.run(8080);
return 0;
}Modify request fields
Most application code reads the request, but the request object also exposes setters.
Set the method:
req.set_method("GET");Set the target and recompute path/query caches:
req.set_target("/users?page=1");Set the body:
req.set_body("new body");Set a header:
req.set_header("X-App", "Vix");Remove a header:
req.remove_header("X-App");These APIs are mostly useful for middleware, testing, adapters, or advanced integrations.
Set route parameters
Use set_params(...) for advanced code that builds or adapts requests.
vix::Request::ParamMap params;
params["id"] = "42";
req.set_params(std::move(params));Normal route handlers should use req.param(...) instead.
Copy request with parameters
Use with_params(...) to return a copy of a request with new route parameters.
auto next_req = req.with_params({
{"id", "42"}
});This is mostly used internally by the request handler adapter.
Request lifecycle
A request is usually created by the HTTP session.
Transport read
-> HTTP parser
-> ParsedRequestHead
-> Request
-> Router
-> RequestHandler
-> user handlerApplication code normally receives it here:
app.get("/path", [](vix::Request &req, vix::Response &res)
{
// use req here
});Request and routing
The router uses:
req.method()
req.target()
req.path()Route parameters are added before the final user handler runs.
req.param("id");Query parameters are parsed from the target.
req.query_value("page");Request and middleware
Middleware receives the same request object as the handler.
app.use([](vix::Request &req, vix::Response &res, vix::App::Next next)
{
(void)res;
vix::print(req.method(), req.path());
next();
});Middleware can read request data, validate it, or attach state.
Complete example
#include <vix.hpp>
#include <string>
struct CurrentUser
{
std::string id;
};
int main()
{
vix::App app;
app.use("/api", [](vix::Request &req, vix::Response &res, vix::App::Next next)
{
res.header("X-API", "Vix");
next();
});
app.protect("/api/private", [](vix::Request &req, vix::Response &res, vix::App::Next next)
{
const std::string token = req.header("Authorization");
if (token.empty())
{
res.status(401).json({
{"error", "missing authorization header"}
});
return;
}
req.state().set(CurrentUser{"42"});
next();
});
app.get("/api/users/{id}", [](vix::Request &req, vix::Response &res)
{
res.json({
{"id", req.param("id")},
{"page", req.query_value("page", "1")},
{"method", req.method()},
{"path", req.path()}
});
});
app.post("/api/echo", [](vix::Request &req, vix::Response &res)
{
res.json({
{"body", req.body()}
});
});
app.get("/api/private/me", [](vix::Request &req, vix::Response &res)
{
const auto &user = req.state().get<CurrentUser>();
res.json({
{"id", user.id}
});
});
app.run(8080);
return 0;
}API summary
| API | Purpose |
|---|---|
method() | Return the HTTP method. |
set_method(method) | Set the HTTP method. |
target() | Return the full request target. |
set_target(target) | Set the target and recompute path/query data. |
path() | Return the path without query string. |
query_string() | Return the raw query string. |
query() | Return parsed query parameters. |
has_query(name) | Check whether a query parameter exists. |
query_value(name, fallback) | Return a query parameter value. |
params() | Return route parameters. |
set_params(params) | Replace route parameters. |
has_param(name) | Check whether a route parameter exists. |
param(name, fallback) | Return a route parameter value. |
headers() | Return all headers. |
set_headers(headers) | Replace all headers. |
header(name) | Return one header value. |
has_header(name) | Check whether a header exists. |
set_header(name, value) | Set one header. |
remove_header(name) | Remove one header. |
body() | Return the request body. |
set_body(body) | Replace the request body. |
json() | Parse and return the body as JSON. |
json_as<T>() | Convert the JSON body to type T. |
has_state() | Check whether state storage exists. |
state() | Access request-scoped state. |
has_state_type<T>() | Check whether state contains T. |
with_params(params) | Return a request copy with new parameters. |
Best practices
Use path() when matching or logging the route path.
vix::print(req.path());Use target() when you need the original path plus query string.
vix::print(req.target());Use fallbacks for optional query parameters.
const std::string page = req.query_value("page", "1");Use route parameters for resource identifiers.
const std::string id = req.param("id");Use middleware and RequestState for authenticated user data.
req.state().set(CurrentUser{"42"});Validate input before using it.
if (!req.has_query("q"))
{
res.status(400).json({{"error", "missing q"}});
return;
}Next steps
Read the next pages: