Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Validation

The optional validation feature makes generated models derive serde_valid::Validate, with field attributes taken from the schema’s constraints.

[dependencies]
openapi-trait = { version = "1", features = ["validation"] }
serde_valid = "2"
use openapi_trait::serde_valid::Validate as _;

fn main() {
    let ok = pets::NewPet {
        name: "doggie".into(),
        status: None,
    };
    assert!(ok.validate().is_ok());

    // `name` has `minLength: 1` in the spec.
    let empty = pets::NewPet {
        name: String::new(),
        status: None,
    };
    let err = empty.validate().unwrap_err();
    println!("{err}");
}

Unlike serde and serde_json, serde_valid must be a direct dependency of your crate. Its Validate derive expands to paths that start with ::serde_valid, and it has no option to point them elsewhere. Without the dependency, the build fails with “cannot find serde_valid in the list of imported crates”. Use major version 2, the same as openapi-trait, so cargo resolves both to one copy. openapi_trait::serde_valid is then the same crate, so either path works for importing Validate.

Constraint mapping

OpenAPI keywordserde_valid attribute
minLength / maxLength / patternmin_length / max_length / pattern
minimum / maximum (+ exclusiveMinimum / exclusiveMaximum)minimum / maximum (or exclusive_minimum / exclusive_maximum)
multipleOfmultiple_of
minItems / maxItems / uniqueItemsmin_items / max_items / unique_items
$ref / inline object / oneOf·anyOf·allOf fieldbare #[validate] (recurses into the nested model)

Opt-in and non-enforcing

  • Nothing calls .validate() for you. Neither the server nor the client rejects invalid values automatically. Call it in your handlers or before sending.
  • Feature off, no change. Without the feature, the generated code is exactly the same as before.
  • Optional recursive fields aren’t checked. serde_valid can’t recurse into Option<Box<T>>, so the optional field that closes a cycle in a recursive schema gets no #[validate].
  • Type aliases can’t be validated directly. A top-level schema that becomes an alias (for example pub type Name = String;) is only checked where it appears as a struct field.