#[skip_serializing_none]
Expand description

Add skip_serializing_if annotations to Option fields.

The attribute can be added to structs and enums.

Import this attribute with use serde_with::skip_serializing_none;.

Example

JSON APIs sometimes have many optional values. Missing values should not be serialized, to keep the serialized format smaller. Such a data type might look like:

#[derive(Serialize)]
struct Data {
    #[serde(skip_serializing_if = "Option::is_none")]
    a: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    b: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    c: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    d: Option<bool>,
}

The skip_serializing_if annotation is repetitive and harms readability. Instead, the same struct can be written as:

#[skip_serializing_none]
#[derive(Serialize)]
struct Data {
    a: Option<String>,
    b: Option<u64>,
    c: Option<String>,
    // Always serialize field d even if None
    #[serialize_always]
    d: Option<bool>,
}

Existing skip_serializing_if annotations will not be altered.

If some values should always be serialized, then the serialize_always can be used.

Limitations

The serialize_always cannot be used together with a manual skip_serializing_if annotations, as these conflict in their meaning. A compile error will be generated if this occurs.

The skip_serializing_none only works if the type is called Option, std::option::Option, or core::option::Option. Type aliasing an Option and giving it another name, will cause this field to be ignored. This cannot be supported, as proc-macros run before type checking, thus it is not possible to determine if a type alias refers to an Option.

type MyOption<T> = Option<T>;

#[skip_serializing_none]
#[derive(Serialize)]
struct Data {
    a: MyOption<String>, // This field will not be skipped
}

Likewise, if you import a type and name it Option, the skip_serializing_if attributes will be added and compile errors will occur, if Option::is_none is not a valid function. Here the function Vec::is_none does not exist and therefore the example fails to compile.

use std::vec::Vec as Option;

#[skip_serializing_none]
#[derive(Serialize)]
struct Data {
    a: Option<String>,
}