How can I deserialize an optional field with custom functions using Serde?

The default behaviour of struct deserialization is to assign fields with their respective default value when they are not present in their serialized form. Note that this is different from the container #[serde(default)] attribute, which fills in the fields with the struct’s default value.

#[derive(Debug, PartialEq, Deserialize)]
pub struct Foo<'a> {
    x: Option<&'a str>,
}

let foo: Foo = serde_json::from_str("{}")?;
assert_eq!(foo, Foo { x: None });

However, this rule changes when we use another deserializer function (#[serde(deserialize_with = "path")]). A field of type Option here no longer tells the deserializer that the field may not exist. Rather, it suggests that there is a field with possible empty or null content (none in Serde terms). In serde_json for instance, Option<String> is the JavaScript equivalent to “either null or string” (null | string in TypeScript / Flow notation). This code below works fine with the given definition and date deserializer:

let test: Test = serde_json::from_str(r#"{"i": 5, "date": null}"#)?;
assert_eq!(test.i, 5);
assert_eq!(test.date, None);

Luckily, the deserialization process can become more permissive just by adding the serde(default) attribute (Option::default yields None):

#[derive(Debug, Serialize, Deserialize)]
struct Test {
    pub i: u64,

    #[serde(default)]
    #[serde(with = "date_serde")]
    pub date: Option<NaiveDate>,
}

Playground

See also:

Leave a Comment