You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The current Drogon API lacks a convenient and safe mechanism for storing per-request data (e.g., user_id, tenant info, tracing context) that can be accessed throughout the request lifecycle (middlewares, handlers, filters, etc.).
How Attribute Addition Looks NOW
Currently, to store data with a request, you have to use the getAttributes() method, which returns a reference to the internal std::unordered_map<std::string, std::any> map:
// In middleware - examplevoidAuthMiddleware::invoke(const HttpRequestPtr& req, MiddlewareNextCallback&& next)
{
int userId = authenticateUser(req);
if (userId > 0) {
// Adding attribute - unsafe and inconvenient
req->getAttributes().insert("user_id", userId);
req->getAttributes()["user_role"] = getUserRole(userId);
}
next(req);
}
// In controller - readingvoidUserController::getProfile(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback)
{
// Reading - requires manual casting and error handlingauto& attrs = req->getAttributes();
auto it = attrs.find("user_id");
if (it != attrs.end()) {
try {
int userId = std::any_cast<int>(it->second);
// Use userId...
} catch (const std::bad_any_cast& e) {
// Error handling - hard to debug
LOG_ERROR << "Type mismatch: " << e.what();
}
}
// Alternative way using Attributes::get<T>() method:// std::string userId = req->getAttributes()->get<std::string>("user_id");// But this returns a reference to a default value if key doesn't exist,// and still lacks thread safety.
}
Problems with the current approach:
Lack of type safety: std::any_cast can throw an exception on wrong type.
Inconvenient API: Need to manually search the map, handle iterators.
No thread safety: Direct map access is not synchronized - risk of race conditions in multi-threaded environments.
Easy mistakes: Can mix up keys, forget to check existence.
No encapsulation: User must know internal implementation (the map).
How the Solution Could Look
Add dedicated methods to HttpRequest for attribute management:
// In middleware - new APIvoidAuthMiddleware::invoke(const HttpRequestPtr& req, MiddlewareNextCallback&& next)
{
int userId = authenticateUser(req);
if (userId > 0) {
// Easy and safe addition
req->setAttribute("user_id", userId)
->setAttribute("user_role", getUserRole(userId));
}
next(req);
}
// In controller - safe readingvoidUserController::getProfile(const HttpRequestPtr& req, std::function<void(const HttpResponsePtr&)>&& callback)
{
// Type-safe reading with optionalauto userId = req->getAttribute<int>("user_id");
auto userRole = req->getAttribute<std::string>("user_role");
if (!userId || *userRole != "admin") {
auto resp = HttpResponse::newHttpJsonResponse(Json::Value(Json::nullValue));
resp->setStatusCode(k403Forbidden);
returncallback(resp);
}
// Use *userId safely...
}
Benefits of the new approach:
Type safety: getAttribute<T>() returns std::optional<T>, automatically handles type errors.
Convenient API: Method chaining, simple methods instead of map manipulation.
Solves a real problem: Request context is a common need in web frameworks for passing data between middlewares and handlers. While Drogon provides getAttributes(), a more convenient and safe API would improve developer experience, similar to req.locals in Express.js or g in Flask.
Low risk:
Full backward compatibility (existing getAttributes() remains).
Only adds new methods, doesn't change existing ones.
No performance impact (mutex only on attribute access).
Value added:
Makes writing cleaner code easier (middleware patterns).
Improves safety (type safety, thread safety).
Easy to implement (2-3 days of work).
Increases framework attractiveness for new users.
Small changes: Only a few files (HttpRequest.h, HttpRequestImpl.h/.cc, tests, docs).
Community support: Similar proposals were accepted in Drogon (e.g., middleware API).
Arguments AGAINST (possible concerns):
Is the problem big enough?: Some might say "use getAttributes() and live with it". But this ignores safety and convenience.
Alternatives: Could use thread-local global variables, but that's an anti-pattern (not thread-safe for concurrent requests).
Complexity: Adding mutex may have minimal performance impact in high-throughput applications.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Request Context Storage: Problem and Solution
Problem
The current Drogon API lacks a convenient and safe mechanism for storing per-request data (e.g., user_id, tenant info, tracing context) that can be accessed throughout the request lifecycle (middlewares, handlers, filters, etc.).
How Attribute Addition Looks NOW
Currently, to store data with a request, you have to use the
getAttributes()method, which returns a reference to the internalstd::unordered_map<std::string, std::any>map:Problems with the current approach:
std::any_castcan throw an exception on wrong type.How the Solution Could Look
Add dedicated methods to
HttpRequestfor attribute management:Benefits of the new approach:
getAttribute<T>()returnsstd::optional<T>, automatically handles type errors.std::shared_mutexsynchronizes access.hasAttribute(),removeAttribute(),clearAttributes().Is This Worth a PR?
Arguments FOR (worth doing a PR):
Solves a real problem: Request context is a common need in web frameworks for passing data between middlewares and handlers. While Drogon provides
getAttributes(), a more convenient and safe API would improve developer experience, similar toreq.localsin Express.js orgin Flask.Low risk:
getAttributes()remains).Value added:
Small changes: Only a few files (HttpRequest.h, HttpRequestImpl.h/.cc, tests, docs).
Community support: Similar proposals were accepted in Drogon (e.g., middleware API).
Arguments AGAINST (possible concerns):
Is the problem big enough?: Some might say "use
getAttributes()and live with it". But this ignores safety and convenience.Alternatives: Could use thread-local global variables, but that's an anti-pattern (not thread-safe for concurrent requests).
Complexity: Adding mutex may have minimal performance impact in high-throughput applications.
Beta Was this translation helpful? Give feedback.
All reactions