#serialization #serde-urlencoded #serde #urlencoded

no-std serde_html_form

(De-)serialization support for the application/x-www-form-urlencoded format

15 unstable releases (3 breaking)

0.4.0 Jan 6, 2026
0.3.2 Dec 25, 2025
0.2.8 Sep 14, 2025
0.2.7 Dec 19, 2024
0.1.0 Apr 19, 2022

#99 in Encoding

Download history 106725/week @ 2025-10-14 108048/week @ 2025-10-21 95013/week @ 2025-10-28 102299/week @ 2025-11-04 92653/week @ 2025-11-11 102954/week @ 2025-11-18 107839/week @ 2025-11-25 119821/week @ 2025-12-02 119812/week @ 2025-12-09 117007/week @ 2025-12-16 64930/week @ 2025-12-23 70019/week @ 2025-12-30 127813/week @ 2026-01-06 147667/week @ 2026-01-13 166329/week @ 2026-01-20 206219/week @ 2026-01-27

670,660 downloads per month
Used in 277 crates (41 directly)

MIT license

80KB
2K SLoC

serde_html_form

(De-)serialization support for the application/x-www-form-urlencoded format.

This crate is a Rust library for serializing to and deserializing from the application/x-www-form-urlencoded format. It is built upon serde, a high performance generic serialization framework and form_urlencoded, a urlencoded parser for Rust (part of Servo).

It is a fork of serde_urlencoded, with additional support for maps or structs with fields of sequence type (e.g. Vec<String>). It also supports Optional numerical values, treating foo= as foo: None.

Examples

Sequences like value=x&value=y:

use serde::Deserialize;

#[derive(Debug, PartialEq, Deserialize)]
struct Form {
    // By default, at least one occurrence of this field must be present (this
    // is mandated by how serde works).
    //
    // Since this is usually not desired, use `serde(default)` to instantiate
    // this struct's field with a `Default` value if input doesn't contain that
    // field.
    #[serde(default)]
    value: Vec<String>,
}

assert_eq!(
    serde_html_form::from_str("value=&value=abc"),
    Ok(Form { value: vec!["".to_owned(), "abc".to_owned()] })
);
assert_eq!(
    serde_html_form::from_str(""),
    Ok(Form { value: vec![] })
);

Sequences like value[]=x&value[]=y:

use serde::Deserialize;

#[derive(Debug, PartialEq, Deserialize)]
struct Form {
    // If you want to support `value[]=x&value[]=y`, you can use
    // `serde(rename)`. You could even use `serde(alias)` instead to allow both,
    // but note that mixing both in one input string would also be allowed then.
    #[serde(default, rename = "value[]")]
    value: Vec<String>,
}

assert_eq!(
    serde_html_form::from_str("value[]=x&value[]=y"),
    Ok(Form { value: vec!["x".to_owned(), "y".to_owned()] })
);
assert_eq!(
    serde_html_form::from_str("value[]=hello"),
    Ok(Form { value: vec!["hello".to_owned()] })
);

Optional values:

use serde::Deserialize;

#[derive(Debug, PartialEq, Deserialize)]
struct Form {
    // Finally, this crate also supports deserializing empty values as `None`
    // if your values are `Option`s.
    // Note that serde's `Deserialize` derive implicitly allows omission of
    // `Option`-typed fields (except when combined with some other attributes).
    single: Option<u32>,
    // Not using `serde(default)` here to require at least one occurrence.
    at_least_one: Vec<Option<u32>>,
}

assert_eq!(
    serde_html_form::from_str("at_least_one=5"),
    Ok(Form {
        // Implicit `serde(default)` in action.
        single: None,
        // `serde_html_form`'s support for optional values being used.
        at_least_one: vec![Some(5)],
    })
);
assert_eq!(
    serde_html_form::from_str("at_least_one=&single=1&at_least_one=5"),
    Ok(Form {
        single: Some(1),
        at_least_one: vec![
            // Empty strings get deserialized as `None` for fields of builtin
            // numerical types. Use `serde_html_form::empty_as_none` if you want
            // this behavior for fields of other types.
            None,
            // It's no problem that the `at_least_one` field repetitions are
            // not consecutive (single comes in between).
            Some(5),
        ]
    })
);
assert!(
    serde_html_form::from_str::<Form>("").is_err(),
    "at_least_one is not part of the input"
);

License

This crate is licensed under the MIT license.

Dependencies

~81–460KB