Structs

Parse vs validate

When to parse input into a struct and when to validate an existing value, and which field names each one uses.

Structs from schema! and #[derive(Validate)] can be checked in two directions.

parse / parse_value / vld_parsevalidate / is_valid
InputJSON (string, bytes, file, Value)an existing Rust value that implements Serialize
Outputa new struct, with transforms and defaults appliedOk(()) or Err(VldError)
Field namesdeserialize namesserialize names
Typical userequest bodies, config files, messagesdata built in code, before saving or sending
use vld::prelude::*;

vld::schema! {
    #[derive(Debug, serde::Serialize)]
    pub struct Account {
        pub email: String => vld::string().email(),
        pub balance: f64 => vld::number().non_negative(),
    }
}

// Incoming data:
let acc = Account::parse(r#"{"email": "ada@example.com", "balance": 10}"#).unwrap();

// Data changed in code:
let mut changed = acc;
changed.balance -= 25.0;
assert!(!Account::is_valid(&changed));
let err = Account::validate(&changed).unwrap_err();
assert_eq!(err.issues[0].code.key(), "too_small");

validate serializes the value with serde and runs the same field schemas. Because the value goes through Serialize, the serialize names apply. With different serialize and deserialize names (rename(serialize = "a", deserialize = "b") or rename_all(serialize = ..., deserialize = ...)) a value serialized by your struct still validates.

Any schema also has schema.validate(&value) and schema.is_valid(&value) for single values:

assert!(vld::string().email().is_valid(&"ada@example.com"));
assert!(vld::array(vld::u8()).validate(&vec![1, 2, 3]).is_ok());

impl_rules! adds validate() / is_valid() as instance methods to structs you did not declare with schema!: see impl_rules!.