Query string parameters
When handling incoming requests sometimes it is necessary to
deal with query string parameter.
For example, the following URL: http://example.com/location?country=canada&minrating=4&mindate=20180101
has 3 query parameters.
Though one can obtain a raw query string from request header (see Request header)
it is more convenient to use restinio::parse_query() function to
get a key-value interface object to work with parameters:
query_string_params_t parse_query( string_view_t query_string );
Class query_string_params_t has the following interface:
class query_string_params_t
{
// ...
string_view_t operator [] ( string_view_t key ) const;
optional_t< string_view_t > get_param( string_view_t key ) const noexcept;
bool has( string_view_t key ) const noexcept;
auto size() const noexcept;
bool empty() const noexcept;
auto begin() const noexcept;
auto end() const noexcept;
optional_t< string_view_t > tag() const noexcept;
// ...
};
Parameters values are represented with string view.
And of course one can cast parameters values with restinio::cast_to<T>().
A sample code for working with query string parameters:
restinio::request_handling_status_t handler( restinio::request_handle_t req )
{
if( restinio::http_method_get() == req->header().method() )
{
std::ostringstream sout;
sout << "GET request to '" << req->header().request_target() << "'\n";
// Query params.
const auto qp = restinio::parse_query( req->header().query() );
if( 0 == qp.size() )
{
sout << "No query parameters.";
}
else
{
sout << "Query params ("<< qp.size() << "):\n";
for( const auto p : qp )
{
sout << "'"<< p.first << "' => "<< p.second << "'\n";
}
}
if( qp.has( "debug" ) && qp[ "debug" ] == "true" )
{
std::cout << sout.str() << std::endl;
}
req->create_response()
.append_header( restinio::http_field::server, "RESTinio query string params server" )
.append_header_date_field()
.append_header( restinio::http_field::content_type, "text/plain; charset=utf-8" )
.set_body( sout.str() )
.done();
return restinio::request_accepted();
}
return restinio::request_rejected();
}
But it is more convenient to use special functions to get values from restinio key-value objects:
value_or() and opt_value(), refer to Get values from RESTinio key-value containers section for details.
See also a full sample.
Additional features of parse_query
Parsing traits
The parse_query function is a template function with the default value
for its single template parameter. A simple call of:
auto params = restinio::parse_query("name=A*&location=L*");
is just a shorthand for:
auto params = restinio::parse_query<
restinio::parse_query_traits::restinio_defaults>("name=A*&location=L*");
A call to parse_query can be explicitly parametrized by a traits class.
This traits class defines how various characters from a query-string should
be iterpreted.
A traits parameter is necessary because there is no an official specificaton
for query-string representation. The RFC3986 tells that any of characters from
sub-delims character set can be used non-percent-encoded. But application/x-www-form-urlencoded allows only
*, -, . and _. If JavaScript method encodeURIComponent is
used for building the query-string, then symbols like *, (, ) and
! will be non-percent-encoded. And browsers like Chrome do not
percent-encode symbols from gen-delims like [ and ]. A traits
parameter tells RESTinio which symbols are enabled in non-percent-encoded form.
Since v.0.6.5 there are several ready to use traits in restinio::parse_query_traits namespace:
x_www_form_urlencoded. Follows application/x-www-form-urlencoded serializer and byte serializer rules. OnlyA..Z,a..z,0..9,*,-,.,_and+can be used non-percent-encoded.name=valuepairs are separated by&;javascript_compatible. Follows the behavior of JavaScript’sencodeURIComponent. SymbolsA..Z,a..z,0..9,!,',(,),*,-,.,_,~and+can be used non-percent-encoded.name=valuepairs are separated by&;restinio_defaults. Implements the behavior of early versions of RESTinio. SymbolsA..Z,a..z,0..9,-,.,_,~and+can be used non-percent-encoded.name=valuepairs can be separated by∨;relaxed. Allows much wider set of non-percent-encoded symbols.
A user can select an appropriate traits class or define its own.
For example, javascript compatible can be used to parse query strings
formed by JavaScript code:
auto params = restinio::parse_query<
restinio::parse_query_traits::javascript_compatible>("name=A*&location=L*");
Support for “web beacon”
Since v.0.4.9 RESTinio has the support for web beacon. It means that if a query string
has the form http://example.com/resource?beacon then the value of
beacon will be available via query_string_params_t::tag() method.
try_parse_query function template
Since v.0.6.5 there is another version of parse_query function: try_parse_query function template. It does the same thing as parse_query but doesn’t throw an exception if a query-string has illegal format.
The try_parse_query function returns expected type that contains query_string_params_t object if parsing was successful, or parse_query_failure_t otherwise.
Usage example:
auto parse_result = restinio::try_parse_query<
restinio::parse_query_traits::relaxed>("a=[&b=]&c=(&d=)");
if(!parse_result) {
std::cerr << "unable to parse query-string, error: "
<< parse_result.error().description() << std::endl;
return ...;
}
else {
const restinio::query_string_params_t & params = *parse_result;
... // Working with query-string content.
}
Unlike parse_query the try_parse_query requires explicit specification of traits class.
NOTE. The try_parse_query is not noexcept function. It doesn’t throw if query-string is ill-formed. But it can throw on other failures (like failed memory allocations).