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=value
pairs 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=value
pairs 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=value
pairs can be separated by&
or;
;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).