2.0 KiB
title, order, status
| title | order | status |
|---|---|---|
| S12. Pass Data Between Handlers with res.user_data | 31 | draft |
Say your pre-request handler decodes an auth token and you want the route handler to use the result. That "data handoff between handlers" is what res.user_data is for — it holds values of arbitrary types.
Basic usage
struct AuthUser {
std::string id;
std::string name;
bool is_admin;
};
svr.set_pre_request_handler(
[](const httplib::Request &req, httplib::Response &res) {
auto token = req.get_header_value("Authorization");
auto user = decode_token(token); // decode the auth token
res.user_data.set("user", user);
return httplib::Server::HandlerResponse::Unhandled;
});
svr.Get("/me", [](const httplib::Request &req, httplib::Response &res) {
auto *user = res.user_data.get<AuthUser>("user");
if (!user) {
res.status = 401;
return;
}
res.set_content("Hello, " + user->name, "text/plain");
});
user_data.set() stores a value of any type, and user_data.get<T>() retrieves it. If you give the wrong type you get nullptr back — so be careful.
Typical value types
Strings, numbers, structs, std::shared_ptr — anything copyable or movable works.
res.user_data.set("user_id", std::string{"42"});
res.user_data.set("is_admin", true);
res.user_data.set("started_at", std::chrono::steady_clock::now());
Where to set, where to read
The usual flow is: set it in set_pre_routing_handler() or set_pre_request_handler(), read it in the route handler. Pre-request runs after routing, so you can combine it with req.matched_route to set values only for specific routes.
A gotcha
user_data lives on Response, not Request. That's because handlers get Response& (mutable) but only const Request&. It looks odd at first, but it makes sense once you think of it as "the mutable context shared between handlers."
Warning:
user_data.get<T>()returnsnullptrwhen the type doesn't match. Use the exact same type on set and get. Storing asAuthUserand fetching asconst AuthUserwon't work.