Expand description
Serde support for querystring-style strings
Querystrings are not formally defined and loosely take the form of nested urlencoded queries.
This library aims for compatability with the syntax of
qs and also of the
Rack::Utils::parse_nested_query
implementation.
For users who do not require nested URL parameters, it is highly
recommended that the serde_urlencoded
crate is used instead, which
will almost certainly perform better for deserializing simple inputs.
§Supported Types
At the top level, serde_qs
only supports struct
, map
, and enum
.
These are the only top-level structs which can be de/serialized since
Querystrings rely on having a (key, value) pair for each field, which
necessitates this kind of structure.
However, after the top level you should find all supported types can be de/serialized.
Note that integer keys are reserved for array indices. That is, a string of
the form a[0]=1&a[1]=3
will deserialize to the ordered sequence a = [1,3]
.
§Usage
See the examples folder for a more detailed introduction.
Serializing/Deserializing is designed to work with maps and structs.
#[macro_use]
extern crate serde_derive;
extern crate serde_qs as qs;
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct Address {
city: String,
postcode: String,
}
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct QueryParams {
id: u8,
name: String,
address: Address,
phone: u32,
user_ids: Vec<u8>,
}
let params = QueryParams {
id: 42,
name: "Acme".to_string(),
phone: 12345,
address: Address {
city: "Carrot City".to_string(),
postcode: "12345".to_string(),
},
user_ids: vec![1, 2, 3, 4],
};
let rec_params: QueryParams = qs::from_str("\
name=Acme&id=42&phone=12345&address[postcode]=12345&\
address[city]=Carrot+City&user_ids[0]=1&user_ids[1]=2&\
user_ids[2]=3&user_ids[3]=4")
.unwrap();
assert_eq!(rec_params, params);
§Strict vs Non-Strict modes
serde_qs
supports two operating modes, which can be specified using
Config
, and is all about how serde_qs
handles square brackets.
Techncially, square brackets should be encoded in URLs as %5B
and %5D
.
However, they are often used in their raw format to specify querystrings
such as a[b]=123
.
In strict mode, serde_qs
will only tolerate unencoded square brackets
to denote nested keys. So a[b]=123
will decode as {"a": {"b": 123}}
.
This means that encoded square brackets can actually be part of the key.
a[b%5Bc%5D]=123
becomes {"a": {"b[c]": 123}}
.
However, since some implementations will automatically encode everything
in the URL, we also have a non-strict mode. This means that serde_qs
will assume that any encoded square brackets in the string were meant to
be taken as nested keys. From the example before, a[b%5Bc%5D]=123
will
now become {"a": {"b": {"c": 123 }}}
.
Non-strict mode can be useful when, as said before, some middleware automatically encodes the brackets. But care must be taken to avoid using keys with square brackets in them, or unexpected things can happen.
§Flatten workaround
A current known limitation
in serde
is deserializing #[serde(flatten)]
structs for formats which
are not self-describing. This includes query strings: 12
can be an integer
or a string, for example.
We suggest the following workaround:
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_qs as qs;
extern crate serde_with;
use serde_with::rust::display_fromstr::deserialize as deserialize_fromstr;
#[derive(Deserialize, Serialize, Debug, PartialEq)]
struct Query {
a: u8,
#[serde(flatten)]
common: CommonParams,
}
#[derive(Deserialize, Serialize, Debug, PartialEq)]
struct CommonParams {
#[serde(deserialize_with="deserialize_fromstr")]
limit: u64,
#[serde(deserialize_with="deserialize_fromstr")]
offset: u64,
#[serde(deserialize_with="deserialize_fromstr")]
remaining: bool,
}
fn main() {
let params = "a=1&limit=100&offset=50&remaining=true";
let query = Query { a: 1, common: CommonParams { limit: 100, offset: 50, remaining: true } };
let rec_query: Result<Query, _> = qs::from_str(params);
assert_eq!(rec_query.unwrap(), query);
}
§Use with actix_web
extractors
The actix
feature enables the use of serde_qs::actix::QsQuery
, which
is a direct substitute for the actix_web::Query
and can be used as an extractor:
fn index(info: QsQuery<Info>) -> Result<String> {
Ok(format!("Welcome {}!", info.username))
}
Support for actix-web 2.0.0
is available via the actix2
feature.
§Use with warp
filters
The warp
feature enables the use of serde_qs::warp::query()
, which
is a substitute for the warp::query::query()
filter and can be used like this:
serde_qs::warp::query(Config::default())
.and_then(|info| async move {
Ok::<_, Rejection>(format!("Welcome {}!", info.username))
})
.recover(serde_qs::warp::recover_fn);
Structs§
- To override the default serialization parameters, first construct a new Config.
- A serializer for the querystring format.
Enums§
- Error type for
serde_qs
.
Functions§
- Deserializes a querystring from a
&[u8]
. - Deserializes a querystring from a
&str
. - Serializes a value into a querystring.
- Serializes a value into a generic writer object.