ferro_rs/validation/mod.rs
1//! Request validation for Ferro framework.
2//!
3//! Provides Laravel-inspired validation with declarative rules.
4//!
5//! ## Flash round-trip (Phase 137)
6//!
7//! On validation failure a POST handler can redirect back and preserve both
8//! errors and old form input in the session flash:
9//!
10//! ```rust,ignore
11//! use ferro_rs::validation::{Validator, rules::*};
12//! use ferro_rs::rules;
13//!
14//! // POST handler
15//! let data = req.input::<serde_json::Value>().await?;
16//! if let Err(e) = Validator::new(&data)
17//! .rules("name", rules![required()])
18//! .validate()
19//! {
20//! let referer = req.header("Referer");
21//! return e.with_old_input(&data).redirect_back(referer);
22//! }
23//!
24//! // GET handler — repopulate form fields
25//! InputProps {
26//! default_value: req.old("name"),
27//! error: req.validation_error("name"),
28//! ..Default::default()
29//! }
30//! ```
31//!
32//! # Example
33//!
34//! ```rust,ignore
35//! use ferro_rs::validation::{Validator, rules};
36//!
37//! let data = serde_json::json!({
38//! "email": "user@example.com",
39//! "password": "secret123",
40//! "age": 25
41//! });
42//!
43//! let validator = Validator::new(&data)
44//! .rules("email", rules![required, email])
45//! .rules("password", rules![required, min(8)])
46//! .rules("age", rules![required, integer, min(18)]);
47//!
48//! if let Err(errors) = validator.validate() {
49//! println!("Validation failed: {:?}", errors);
50//! }
51//! ```
52
53mod bridge;
54mod error;
55mod rule;
56mod rules;
57mod validatable;
58mod validator;
59
60pub(crate) use bridge::translate_validation;
61pub use bridge::{register_validation_translator, TranslatorFn};
62pub use error::ValidationError;
63pub use rule::Rule;
64pub use rules::*;
65pub use validatable::Validatable;
66pub use validator::{validate, Validator};
67
68/// Macro for creating a vector of boxed validation rules.
69///
70/// This macro boxes each rule, allowing different rule types to be stored
71/// together in a single vector.
72///
73/// # Example
74///
75/// ```rust,ignore
76/// use ferro_rs::validation::{Validator, rules::*};
77/// use ferro_rs::rules;
78///
79/// let validator = Validator::new(&data)
80/// .rules("email", rules![required(), email()])
81/// .rules("name", rules![required(), string(), max(255)]);
82/// ```
83#[macro_export]
84macro_rules! rules {
85 ($($rule:expr),* $(,)?) => {
86 vec![$(Box::new($rule) as Box<dyn $crate::validation::Rule>),*]
87 };
88}