Basic idea
When describing RESTinio HTTP server there are three abstractions vital for an understanding of how to use it.
http_server_t<Traits>
- a class representing HTTP server.server_settings_t<Traits>
- a class representing server settings.Traits
- a customization type for previous abstractions, that makes it possible to tune concrete server implementation.
Not less of importance is the fact that RESTinio runs on ASIO or Boost::ASIO See details here: ASIO Support. The rest of documentation assumes that a stand-alone ASIO is used.
An instance of asio::io_context
is used to run the server.
RESTinio can use its own privately created asio::io_context
or
it can make use of external io_context instance.
The last case requires some assumptions to be fulfilled
(see Using external io_context).
Traits
Main class http_server_t
is a template class parameterized with a single
template parameter: Traits
. Traits class must specify a set of types used
inside RESTinio, they are:
timer_manager_t;
logger_t;
request_handler_t;
strand_t;
stream_socket_t;
There is a helper classes for working with traits:
template <
typename Timer_Manager,
typename Logger,
typename Request_Handler = default_request_handler_t,
typename Strand = asio::strand< asio::executor >,
typename Socket = asio::ip::tcp::socket >
struct traits_t; // Implementation omitted.
template <
typename Timer_Manager,
typename Logger,
typename Request_Handler = default_request_handler_t >
using single_thread_traits_t =
traits_t< Timer_Manager, Logger, Request_Handler, noop_strand_t >; // Implementation omitted.
Refer to Traits and restinio/traits.hpp for details.
Class http_server_t<Traits>
Class http_server_t<Traits>
is a template class parameterized with a single
template parameter: Traits
. Its meaning is directly depicted in its name,
http_server_t<Traits>
represents HTTP-server. It is handy to consider
http_server_t<Traits>
class as a root class for the rest of RESTinio
ecosystem running behind it, because pretty much all of them are also template
types parameterized with the same Traits parameter.
Class http_server_t<Traits>
has two constructors (simplified to omit verbose
template stuff):
http_server_t(
io_context_holder_t io_context,
server_settings_t<Traits> settings );
template < typename Configurator >
http_server_t(
io_context_holder_t io_context,
Configurator && configurator );
The first is the main one. It obtains io_context
as an asio::io_context
back-end and server settings with the bunch of params.
The second constructor can simplify setting of parameters via generic lambda like this:
http_server_t< my_traits_t > http_server{
restinio::own_io_context(),
[]( auto & settings ){ // Omit concrete name of settings type.
settings
.port( 8080 )
.read_next_http_message_timelimit( std::chrono::seconds( 1 ) )
.handle_request_timeout( std::chrono::milliseconds( 3900 ) )
.write_http_response_timelimit( std::chrono::milliseconds( 100 ) )
.logger( /* logger params */ )
.request_handler( /* request handler params */ );
} };
But in the end, it delegates construction to the first constructor.
RESTinio runs its logic on asio::io_context
, but its internal logic is
separated from maintaining io_context directly, hence allowing to run restinio
on external (specified by user) instance of asio::io_context
(see
Using external io_context). So there is a special
class for wrapping io_context instance and pass it to http_server_t
constructor: io_context_holder_t
. To create such holder use one of the
following functions:
restinio::own_io_context()
– creates and uses its own instance of io_context;restinio::external_io_context(asio::io_context&)
– uses external instance of io_context.
Running server
To run server there are open()/close()
methods :
class http_server_t
{
// ...
public:
template <
typename Server_Open_Ok_CB,
typename Server_Open_Error_CB >
void
open_async(
Server_Open_Ok_CB && open_ok_cb,
Server_Open_Error_CB && open_err_cb )
void
open_sync();
template <
typename Server_Close_Ok_CB,
typename Server_Close_Error_CB >
void
close_async(
Server_Close_Ok_CB && close_ok_cb,
Server_Close_Error_CB && close_err_cb );
void
close_sync();
//...
}
There are sync methods for starting/stopping server and async.
To choose the right method it is necessary to understand
that RESTinio doesn’t start and run io_context that it runs on.
So the user is responsible for running io_context.
Sync versions of open()/close()
methods assume they are called on
the context of a running io_context. For example:
// Create and initialize object.
restinio::http_server_t< my_traits_t > server{
restinio::own_io_context(),
[&]( auto & settings ){
//
settings
.port( args.port() )
// .set_more_params( ... )
.request_handler(
[]( restinio::request_handle_t req ){
// Handle request.
} );
} };
// Post initial action to asio event loop.
asio::post( server.io_context(),
[&] {
// Starting the server in a sync way.
server.open_sync();
} );
// Running server.
server.io_context().run();
Async versions of open()/close()
methods can be used from any thread. But
it is not guaranteed that server is already started when method finishes.
When using open_async() user provides two callbacks, the first one is called
if the server starts successfully, and the second one is for handling an error.
For example:
asio::io_context io_ctx;
restinio::http_server_t< my_traits_t > server{
restinio::external_io_context(io_ctx),
[&]( auto & settings ) { ... } };
// Launch thread on which server will work.
std::thread server_thread{ [&] {
io_ctx.run();
} };
// Start server in async way. Actual start will be performed
// on the context of server_thread.
server.open_async(
// Ok callback. Nothing to do.
[]{},
// Error callback. Rethrow an exception.
[]( auto ex_ptr ) {
std::rethrow_exception( ex_ptr );
} );
...
// Wait while server_thread finishes its work.
server_thread.join();
Refer to restinio/http_server.hpp for details.
Class server_settings_t<Traits>
Class server_settings_t<Traits>
serves to pass settings to
http_server_t<Traits>
. It is defined in restinio/settings.hpp).
For each parameter, a setter/getter pair is provided. While setting most of the parameters is pretty straightforward, there are some parameters with a bit tricky setter/getter semantics. They are request_handler, timer_factory, logger, acceptor_options_setter, socket_options_setter and cleanup_func.
For example setter for request_handler looks like this:
template< typename... PARAMS >
server_settings_t &
request_handler( PARAMS &&... params );
When called an instance of std::unique_ptr<Traits::request_handler_t>
will
be created with specified params
. If no constructor with such parameters
is available, then a compilation error will occur. If request_handler_t
has a
default constructor then it is not mandatory to call setter – the default
constructed instance will be used. But there is an exception for
std::function
type because even though it has a default constructor it will
be useless when constructed in such a way.
The request handler is constructed as unique_ptr, then getter
returns unique_ptr value with ownership, so while manipulating
server_settings_t
object don’t use it.
The same applies to timer_factory, logger parameters, acceptor_options_setter, socket_options_setter and cleanup_func.
When http_server_t
instance is created all the settings are checked in order to be properly instantiated.
Refer to Server settings and restinio/settings.hpp for details.