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.
Strict mode has two parts:
- how
serde_qshandles square brackets - how
serde_qshandles invalid UTF-8 percent decoded characters
§Square Brackets
Technically, 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.
§Invalid UTF-8 Percent Encodings
Sometimes querystrings may have percent-encoded data which does not decode
to UTF-8. In some cases it is useful for this to cause errors, which is how
serde_qs works in strict mode (the default). Whereas in other cases it
can be useful to just replace such data with the unicode replacement
character (� U+FFFD), which is how serde_qs works in non-strict mode.
§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::{serde_as, DisplayFromStr};
#[derive(Deserialize, Serialize, Debug, PartialEq)]
struct Query {
a: u8,
#[serde(flatten)]
common: CommonParams,
}
#[serde_as]
#[derive(Deserialize, Serialize, Debug, PartialEq)]
struct CommonParams {
#[serde_as(as = "DisplayFromStr")]
limit: u64,
#[serde_as(as = "DisplayFromStr")]
offset: u64,
#[serde_as(as = "DisplayFromStr")]
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 actix4, actix3 or actix2 features enable 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 4.0 is available via the actix4 feature.
Support for actix-web 3.0 is available via the actix3 feature.
Support for actix-web 2.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§
- Config
- To override the default serialization parameters, first construct a new Config.
- Serializer
Enums§
- Error
- Error type for
serde_qs.
Functions§
- from_
bytes - Deserializes a querystring from a
&[u8]. - from_
str - Deserializes a querystring from a
&str. - to_
string - Serializes a value into a querystring.
- to_
writer - Serializes a value into a generic writer object.