Skip to main content

Crate deser_urlencoded

Crate deser_urlencoded 

Source
Expand description

Query strings and form data (application/x-www-form-urlencoded) for deser.

use deser::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
struct Search {
    q: String,
    page: Option<u32>,
    #[deser(default)]
    tags: Vec<String>,
}

let search: Search =
    deser_urlencoded::from_str("q=rust+serde&tags=a&tags=b").unwrap();
assert_eq!(search.q, "rust serde");
assert_eq!(search.page, None);
assert_eq!(search.tags, ["a", "b"]);

let query = deser_urlencoded::to_string(&search).unwrap();
assert_eq!(query, "q=rust+serde&tags=a&tags=b");

§Data Model

Everything in a query string is text, the type of a value is only known to the type it’s deserialized into. Keys and values are therefore passed on as lexical atoms which are parsed by the types they are delivered to: numbers parse them, strings take them as they are. Lexical atoms are retained when values are buffered, so flattened structs and internally tagged and untagged enums work as well:

use deser::Deserialize;

#[derive(Debug, Deserialize, PartialEq)]
struct Paginate {
    limit: u32,
    offset: u32,
}

#[derive(Debug, Deserialize, PartialEq)]
#[deser(tag = "type", rename_all = "lowercase")]
enum Query {
    Users {
        active: bool,
        #[deser(flatten)]
        paginate: Paginate,
    },
}

let query: Query = deser_urlencoded::from_str(
    "limit=10&offset=20&active=yes&type=users",
)
.unwrap();
assert_eq!(
    query,
    Query::Users {
        active: true,
        paginate: Paginate { limit: 10, offset: 20 },
    }
);

The input is a map whose keys can repeat (a multimap). Keys can be nested (see Nesting):

query stringdeser
a=1{"a": "1"}
a=1&a=2{"a": "1", "a": "2"} (a repeated key)
a[]=1&a[]=2{"a": ["1", "2"]}
a[0]=1&a[1]=2{"a": ["1", "2"]}
a[1]=1&a[3]=2{"a": {"1": "1", "3": "2"}}
a[b]=1&a[c][]=2{"a": {"b": "1", "c": ["2"]}}
a[0][b]=1&a[1][b]=2{"a": [{"b": "1"}, {"b": "2"}]}

Fields and map values that are collections (like Vec<T> or HashSet<T>) collect the values of all occurrences of their key, also if other keys are between them. A key given once is a collection of one value and a missing key an empty collection. Types that expect a single value receive the last one unless the Context has another DuplicateKeys policy:

use deser::de::DuplicateKeys;
use deser::Context;

#[derive(deser::Deserialize)]
struct Query {
    page: u32,
}

let query: Query = deser_urlencoded::from_str("page=1&page=2").unwrap();
assert_eq!(query.page, 2);

let strict = deser_urlencoded::DeserializerConfig::builder()
    .context(Context::with(DuplicateKeys::Error))
    .build();
assert!(strict.from_str::<Query>("page=1&page=2").is_err());

a[]=1 is always a sequence. Indexes that start at 0 and have no gaps are sequences, other indexes are map keys.

#[derive(deser::Deserialize, Debug, PartialEq)]
struct Filter {
    tag: Vec<String>,
    page: u32,
    user: Vec<String>,
}

assert_eq!(
    deser_urlencoded::from_str::<Filter>("tag=a&page=2&tag=b").unwrap(),
    Filter { tag: vec!["a".into(), "b".into()], page: 2, user: vec![] },
);

The URL standard makes no difference between a and a=, both are the empty value. Empty values are None for optionals if the type does not accept them (page= is None for an Option<u32> and Some("") for an Option<String>). Booleans accept true, yes, on and 1 and false, no, off and 0 (HTML checkboxes send on). Flags which are switched on by giving their key (like ?recursive) use the Flag adapter:

use deser::adapters::Flag;

#[derive(deser::Deserialize)]
struct Tree {
    #[deser(as = Flag)]
    recursive: bool,
}

assert!(
    deser_urlencoded::from_str::<Tree>("recursive").unwrap().recursive
);
assert!(
    deser_urlencoded::from_str::<Tree>("recursive=").unwrap().recursive
);
assert!(
    !deser_urlencoded::from_str::<Tree>("recursive=0").unwrap().recursive
);
assert!(!deser_urlencoded::from_str::<Tree>("").unwrap().recursive);

Keys and values are percent-decoded (+ is a space) before the keys are split, so a%5B%5D=1 (as sent by browsers) is the same as a[]=1. Values which are not UTF-8 after decoding are passed on as bytes. A leading ? is ignored. Keys which do not follow the syntax of the nesting (like a[b) are taken as they are. A key that has a value and nested keys (a=1&a[b]=2) is an error.

Serializing works the other way around (see SerializerConfig), how sequences are written can be configured (see ArrayFormat).

§Streams

Form data is read from a Read with from_reader and written to a Write with to_writer. The configurations also create readers and writers of deser::io (DeserializerConfig::reader and SerializerConfig::writer), the stream serializer (Serializer) and deserializer (StreamDeserializer) work with other kinds of IO too (for instance async runtimes with deser-tokio). The whole stream is read before it’s parsed.

§Features

  • io (enabled by default): reading and writing streams of the standard library, see streams.
  • speedups (enabled by default): has no effect yet, it exists so that all formats have it.

Structs§

Deserializer
Deserializes query strings and form data.
DeserializerConfig
Configures how query strings and form data are deserialized.
DeserializerConfigBuilder
Builds a DeserializerConfig.
Serializer
Serializes values into query strings.
SerializerConfig
Configures how values are serialized to query strings.
SerializerConfigBuilder
Builds a SerializerConfig.
StreamDeserializer
Reads form data from a stream (see deser::stream).

Enums§

ArrayFormat
How sequences are written.
Nesting
How keys are nested.

Functions§

from_reader
Deserializes form data from a reader.
from_slice
Deserializes a value from a query string in a byte slice.
from_str
Deserializes a value from a query string.
to_string
Serializes a value to a query string.
to_writer
Serializes a value as form data to a writer.