Schemas

Modifiers

optional, nullable, nullish, with_default and catch.

Modifiers are methods of the VldSchema trait, so they work on every schema.

Methodnull / missingInvalid valueOutput
.optional()None / NoneerrorOption<T>
.nullable()None / missing_fielderrorOption<T>
.nullish()None / NoneerrorOption<T>
.with_default(v)verrorT
.catch(v)vvT
use vld::prelude::*;

let age = vld::u8().optional();
assert_eq!(age.parse("null").unwrap(), None);
assert_eq!(age.parse("30").unwrap(), Some(30));
assert!(age.parse("-1").is_err());

let page = vld::u32().min(1).with_default(1);
assert_eq!(page.parse("null").unwrap(), 1);
assert!(page.parse("0").is_err()); // present but invalid: still an error

let theme = vld::enumeration(&["light", "dark"]).catch("light".to_string());
assert_eq!(theme.parse(r#""purple""#).unwrap(), "light");

optional, nullable, nullish

They differ on a missing object key and in JSON Schema / TypeScript:

absent keynullJSON SchemaTypeScript (vld-ts)
optional()NoneNonenot requiredx?: T
nullable()missing_fieldNonerequired, T | nullx: T | null
nullish()NoneNonenot required, T | nullx?: T | null

optional() also accepts null, although its schema has no null type: serde writes a None field as null, so validate() of a struct with None must pass. Use nullish() when clients may send null and the schema should say so. partial() makes fields optional. Wrappers (describe, refine, transform, rule, catch, …) keep these semantics.

with_default

The default is used only for null or a missing key. A value that is present and invalid still fails. With openapi, the default is emitted as "default": value (the output type must implement serde::Serialize).

impl_default! builds Default from the field types, not from schema defaults; to get schema defaults, parse an empty object. See schema! macro.

catch

catch(v) returns v on any error, including wrong types. Use it for tolerant reading of optional settings; avoid it for input you need to reject.