Derive Macro Validate

Source
#[derive(Validate)]
{
    // Attributes available to this derive:
    #[validate]
}
Expand description

Implements ValidateArgs for structs and enums.

§Supported type attributes

§args

Defines Args of the ValidateArgs implementation.

#[validate(args(a: i32, b: bool, ...))]

Example:

#[derive(Validate)]
#[validate(args(max_len: usize))]
struct Comment {
    author_id: u64,
    #[validate(char_length(max = max_len))]
    content: String,
}

let comment = Comment {
    author_id: 1,
    content: "Great video! ".repeat(10),
};
assert!(comment.validate_args((150,)).is_ok());
assert!(comment.validate_args((100,)).is_err());

§custom

Validates the entire struct/enum with a custom validation function. The signature of the function must be fn(data: &T, args: (A, B, C, ...)) -> ValidationNode if it has validation parameters, or fn(data: &T, args: (A, B, C, ...)) -> ValidationNode if it doesn’t.

#[validate(custom = func::path)]
#[validate(custom(function = func::path))]
#[validate(custom(function = func::path, args=(...)))]

Example:

#[derive(Validate)]
#[validate(custom = validate_comment)]
struct Comment {
    author_id: u64,
    content: String,
}

fn validate_comment(comment: &Comment) -> ValidationNode {
    let max_len = if comment.author_id == 0 { 200 } else { 100 };
    ValidationNode::field("content", ValidationNode::error_if(
        comment.content.len() > max_len,
        || ValidationError::with_code("length")
    ))
}

let super_comment = Comment {
    author_id: 0,
    content: "Great video! ".repeat(10),
};

let regular_comment = Comment {
    author_id: 1,
    content: "Great video! ".repeat(10),
};

assert!(super_comment.validate().is_ok());
assert!(regular_comment.validate().is_err());

§Supported field attributes

§some

Validates data in Some variant of Option. Accepts all field arguments.

#[validate(some)]
#[validate(some(...))]

Example:

#[derive(Validate)]
struct Input {
    #[validate(some(range(max = 10)))]
    maybe_number: Option<u32>,
}

assert!(Input { maybe_number: None }.validate().is_ok());
assert!(Input { maybe_number: Some(5) }.validate().is_ok());
assert!(Input { maybe_number: Some(20) }.validate().is_err());

§items

Validates all items in a list-like collection. Works with arrays, slices, Vec, VecDeque, HashSet, BTreeSet, LinkedList.

#[validate(items)]
#[validate(items(...))]

Example:

#[derive(Validate)]
struct Input {
    #[validate(items(range(max = 10)))]
    numbers: Vec<u32>,
}

assert!(Input { numbers: vec![] }.validate().is_ok());
assert!(Input { numbers: vec![1, 2, 3] }.validate().is_ok());
assert!(Input { numbers: vec![6, 1, 50] }.validate().is_err());

§fields

Validates all values in a key-value collection. Works with HashMap and BTreeMap.

#[validate(fields)]
#[validate(fields(...))]

Example:

use std::collections::HashMap;

#[derive(Validate)]
struct Input {
    #[validate(fields(char_length(max = 10)))]
    map: HashMap<u32, String>,
}

assert!(Input { map: [].into_iter().collect() }.validate().is_ok());
assert!(Input { map: [(1, "hello".into())].into_iter().collect() }.validate().is_ok());
assert!(Input { map: [(1, "x".repeat(100))].into_iter().collect() }.validate().is_err());

§nested

Validates field using its ValidateArgs implementation.

#[validate]
#[validate(nested)]
#[validate(nested(args(...)))]

Example:

#[derive(Validate)]
struct Child {
    #[validate(range(max = 10))]
    number: u32,
}

#[derive(Validate)]
struct Input {
    #[validate]
    child: Child,
}

assert!(Input { child: Child { number: 5 }}.validate().is_ok());
assert!(Input { child: Child { number: 20 }}.validate().is_err());

§custom

Validates field using a custom validation function. The signature of the function must be fn(data: &T, args: (A, B, C, ...)) -> ValidationNode if it has validation parameters, or fn(data: &T, args: (A, B, C, ...)) -> ValidationNode if it doesn’t.

#[validate(custom = func::path)]
#[validate(custom(function = func::path))]
#[validate(custom(function = func::path, args=(...)))]

Example:

#[derive(Validate)]
struct Input {
    #[validate(custom = validate_username)]
    username: String,
}

fn validate_username(username: &str) -> ValidationNode {
    ValidationNode::error_if(
        !username.chars().all(|a| a.is_alphanumeric()),
        || ValidationError::with_code("non_alpha"),
    )
}

assert!(Input { username: "Alex1990".into() }.validate().is_ok());
assert!(Input { username: "Bob!!!".into() }.validate().is_err());

§range

Checks if a number is in the specified range. Works with all integer and float types.

#[validate(range(min = expr))]
#[validate(range(max = expr))]
#[validate(range(min = expr, max = expr))]

Example:

#[derive(Validate)]
struct Input {
    #[validate(range(min = 1, max = 100))]
    number: u32,
}

assert!(Input { number: 0 }.validate().is_err());
assert!(Input { number: 4 }.validate().is_ok());
assert!(Input { number: 110 }.validate().is_err());

§length

Validates size of a container. Works with arrays, strings, slices, and all standard container types. String length is measures in bytes, not UTF-8 characters.

#[validate(length(min = expr))]
#[validate(length(max = expr))]
#[validate(length(min = expr, max = expr))]
#[validate(length(equal = expr))]

Example:

#[derive(Validate)]
struct Input {
    #[validate(length(max = 2))]
    numbers: Vec<u32>,
}

assert!(Input { numbers: vec![1] }.validate().is_ok());
assert!(Input { numbers: vec![1, 1] }.validate().is_ok());
assert!(Input { numbers: vec![1, 1, 1] }.validate().is_err());

§char_length

Validates size of a string measured in UTF-8 characters. Works with strings and string slices.

#[validate(char_length(min = expr))]
#[validate(char_length(max = expr))]
#[validate(char_length(min = expr, max = expr))]
#[validate(char_length(equal = expr))]

Example:

#[derive(Validate)]
struct Input {
    #[validate(char_length(max = 5))]
    username: String,
}

assert!(Input { username: "Chris".into() }.validate().is_ok());
assert!(Input { username: "María".into() }.validate().is_ok());
assert!(Input { username: "Isabela".into() }.validate().is_err());