RESTinio is a relatively small C ++ 14 library for embedding an HTTP / WebSocket server in C ++ applications. We have tried to make RESTinio easy to use, highly customizable, with decent performance. And, it seems, so far it turns out.
Previously, there were already articles about RESTinio , but they were more about what and how was done in the giblets of the library. Today I would like to talk about what appeared in the fresh version of RESTinio, and why it appeared. And also say a few words about why this release is likely to be the last big update within the 0.6 branch. And what I would like to achieve when working on the 0.7 branch.
Anyone interested, you are welcome under cat.
Main feature of version 0.6.13: chains of synchronous handlers
, 2017- RESTinio, HTTP- C++ . , . , RESTinio ExpressJS. express_router RESTinio.
ExpressJS : middleware. - RESTinio .
. RESTinio , - middleware ExpressJS . , middleware RESTinio.
, . .
, 0.6.13 RESTinio . . not_handled
. - accepted
rejected
, .
, , :
- - ;
- HTTP-;
- ( ) , .
:
auto incoming_req_logger(const restinio::request_handle_t & req)
{
... // .
// .
return restinio::request_not_handled();
}
auto mandatory_fields_checker(const restinio::request_handle_t & req)
{
... // .
if(!ok) {
// .
return req->create_response(restinio::status_bad_request())
...
.done(); // accepted.
}
// .
return restinio::request_not_handled();
}
auto permissions_checker(const restinio::request_handle_t & req)
{
... // .
if(!ok) {
// .
return req->create_response(restinio::status_unauthorized())
...
.done(); // accepted.
}
// .
return restinio::request_not_handled();
}
auto actual_processor(const restinio::request_handle_t & req)
{
... // .
return restinio::request_accepted();
}
, .
-, . RESTinio , .
, , fixed_size_chain_t
:
// .
#include <restinio/sync_chain/fixed_size.hpp>
...
struct my_traits : public restinio::default_traits_t {
using request_handler_t = restinio::sync_chain::fixed_size_chain_t<4>;
};
-, :
restinio::run(restinio::on_this_thread<my_traits>()
.port(...)
.address(...)
.request_handler(
// .
incoming_req_logger,
mandatory_fields_checker,
permissions_checker,
actual_processor)
...
);
, , .
?
.
, RESTinio .
, , , RESTinio . RESTinio : , , , , , , -...
, RESTinio , , , , . - RESTinio . , RESTinio . RESTinio, , , : rejected
accepted
.
, . (.. create_response()...done()
) . - , - done()
.
, , accepted
, RESTinio , . - . , - .
RESTinio accepted
, . RESTinio , .
.
RESTinio . , fixed_size_chain_t
— , RESTinio. . RESTinio , RESTinio .
, not_handled
, rejected
, accepted
. ?
. , - .
. .. , - .
- 0.6.13 . .. , . , RESTinio, , - - . , . , , RESTinio.
, - ?
. - . accepted
.
?
, . . 0.6.13 0.6 . , API RESTinio.
. .
, :
- authentification_handler, ;
- permissions_checker, , ;
- admin_access_logger, ;
- actual_processor, .
user_permissions, . permissions_checker- ( ) admin_access_logger ( ).
, , authentification_handler ?
.
/, -:
struct user_permissions {...};
...
// .
struct per_request_data {
user_permissions user_info_;
... // , - .
};
.. extra-data-factory, .. :
struct my_extra_data_factory {
// extra-data-factory data_t.
using data_t = per_request_data;
// .
void make_within(restinio::extra_data_buffer_t<data_t> buf) {
new(buf.get()) data_t{};
}
};
:
struct my_traits : public restinio::default_traits_t {
using extra_data_factory_t = my_extra_data_factory;
};
, , : . restinio::request_handle_t
restinio::generic_request_handle_t<per_request_data>
:
restinio::request_handling_status_t authentification_handler(
const restinio::generic_request_handle_t<per_request_data> & req);
restinio::request_handling_status_t permissions_checker(
const restinio::generic_request_handle_t<per_request_data> & req);
restinio::request_handling_status_t admin_access_logger(
const restinio::generic_request_handle_t<per_request_data> & req);
restinio::request_handling_status_t actual_processor(
const restinio::generic_request_handle_t<per_request_data> & req);
, .
DefaultConstructible , — . stateful-, , . :
// .
struct per_request_data {
std::shared_ptr<log_stream> log_;
per_request_data(std::shared_ptr<log_stream> log)
: log_{std::move(log)}
{}
};
// .
class my_extra_data_factory {
std::shared_ptr<logger> logger_;
public:
using data_t = per_request_data;
my_extra_data_factory(std::shared_ptr<logger> logger)
: logger_{std::move(logger)}
{}
void make_within(restinio::extra_data_buffer_t<data_t> buf) {
new(buf.get()) data_t{
std::make_shared<log_stream>(logger_)
};
}
};
struct my_traits : public restinio::default_traits_t {
using extra_data_factory_t = my_user_data_factory;
};
auto logger = std::make_shared<logger>(...);
// .
restinio::run(restinio::on_thread_pool<my_traits>(16)
.port(...)
.address(...)
// RESTinio.
.extra_data_factory(std::make_shared<my_user_data_factory>(logger))
.request_handler(...)
);
extra_data
generic_request_t
:
restinio::request_handling_status_t authentification_handler(
const restinio::generic_request_handle_t<per_request_data> & req)
{
... // .
if(!ok) {
// .
return req->create_response(...)...done();
}
else {
// .
req->extra_data().user_info_ = user_permissions{...};
return restinio::request_not_handled();
}
}
restinio::request_handling_status_t permissions_checker(
const restinio::generic_request_handle_t<per_request_data> & req)
{
// .
const auto & user_info = req->extra_data().user_info_;
... // .
}
, generic_request_t<Extra_Data>
, 0.6.13, RESTinio : generic_request_t<Extra_Data>
generic_request_handle_t<Extra_Data>
( std::shared_ptr<generic_request_t<Extra_Data>>
).
, , request_t
request_handle_t
generic_request_t<no_extra_data_factory_t::data_t>
generic_request_handle_t<no_extra_data_factory_t::data_t>
, no_extra_data_factory_t
— .
restinio::traits_t
, restinio::default_traits_t
restinio::default_single_thread_traits_t
no_extra_data_factory_t
extra_data_factory_t
. , request_t
request_handle_t
, .
extra-data express-/easy_parser_router
, express_router, ExpressJS, RESTinio. express_router . , extra-data express_router-.
extra-data , express_router-, express_router- extra-data. :
struct my_extra_data_factory { ... };
struct my_traits : public restinio::default_traits_t {
using extra_data_factory_t = my_extra_data_factory;
using request_handler_t = restinio::router::express_router_t<
restinio::router::std_regex_engine_t,
extra_data_factory_t>;
};
express_router request_handle_t
generic_request_handle_t<my_traits::extra_data_factory_t::data_t>
.
struct my_traits : public restinio::default_traits_t {
using extra_data_factory_t = my_extra_data_factory;
using request_handler_t = restinio::router::easy_parser_router_t<
extra_data_factory_t>;
};
RESTinio-0.7?
, 0.6 0.7.
.
-, RESTinio http-parser. , , . , http-parser ( ), RESTinio. , .
-, RESTinio , . , . , - . ?
-, , , , 0.6 . :
- http/1.1, http/2, http/3;
- , RESTinio , ;
- .
, , 0.6 .
- RESTinio?
RESTinio, , RESTinio.
, , .
, RESTinio . :( ;)
, , RESTinio, Issues Discussions GitHub. Google-. , .
2020- . , , . , RESTinio . , RESTinio .
A significant role in this was played by our users, who risked choosing RESTinio for their tasks. And someone also found the time / opportunity for feedback. Thanks to this, RESTinio was able to get rid of several shortcomings and provide several features.
So I want to say a big thank you to everyone interested in RESTinio. Your attention is very important to us.
And, of course, a huge thanks to everyone using RESTinio. Without you, this project would not have developed.
Well, Happy New Year!