Extending response_builder_t<restinio_controlled_output_t>
Would it be possible to to extend the template specialization in order to add custom methods and/or default behavior to the constructor?
There's a lot of boiler plate between create_response() and done(), for example:
restinio::request_handling_status_t edit::operator()(const restinio::request_handle_t &req, restinio::router::route_params_t params) {
auto &user = list_.get(restinio::cast_to<int>(params["id"]));
user_management::user_modifier(user).apply(nlohmann::json::parse(req->body()));
return req->create_response()
.append_header(restinio::http_field::access_control_allow_origin, "*") // Added on every request
// More CORS Headers...
.append_header(restinio::http_field::content_type, "application/json") // Always true
// Date, Last-Modified, ETag, Accept-Patch ... etc...
.set_body(nlohmann::json(user).dump()) // This is a typical JSON API, it would be nice to have handlers for my custom types
.done();
}
Now it would be very easy to have...
restinio::request_handling_status_t edit::operator()(const restinio::request_handle_t &req, restinio::router::route_params_t params) {
auto &user = list_.get(restinio::cast_to<int>(params["id"]));
user_management::user_modifier(user).apply(nlohmann::json::parse(req->body()));
return add_edit_hedaers(add_api_headers(add_cors_headers(req->create_response())))
.set_body(nlohmann::json(user).dump())
.done();
}
What I would love to have...
restinio::request_handling_status_t edit::operator()(const restinio::request_handle_t &req, restinio::router::route_params_t params) {
auto &user = list_.get(restinio::cast_to<int>(params["id"]));
user_management::user_modifier(user).apply(nlohmann::json::parse(req->body()));
return req->create_response<edit_response_builder>()
.set_body(user)
.done();
}
This begs the question
Why is this class marked final?
https://github.com/Stiffstream/restinio/blob/a6a07d147a04192cd0f590492ce6dd321597d54c/dev/restinio/message_builders.hpp#L257-L259
Response builders use inheritance only to avoid code duplication. Because of that response_builder_t<T> is not designed to be used in class hierarchies.
I think your case can be solved by using your own response-builder class like that:
class edit_response_builder {
restinio::response_builder_t<restinio::restinio_controlled_output_t> builder_;
...
public:
edit_response_builder(restinio::request_t & req) : builder_{req.create_response()} {
add_cors_headers(builder_);
add_api_headers(builder_);
add_edit_headers(builder_);
}
...
edit_response_builder & set_body(std::string body) {
builder_.set_body(std::move(body));
return *this;
}
auto done() { return builder_.done(); }
};
...
restinio::request_handling_status_t edit::operator()(const restinio::request_handle_t &req, restinio::router::route_params_t params) {
auto &user = list_.get(restinio::cast_to<int>(params["id"]));
user_management::user_modifier(user).apply(nlohmann::json::parse(req->body()));
return edit_response_builder{*req}
.set_body(user)
.done();
}
Typically templates are not bothered by inheritance. :thinking:
That's a very interesting solution, I'll give it a shot!