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 async_rule;
54mod async_validator;
55mod bridge;
56mod constraint_map;
57mod error;
58mod rule;
59mod rules;
60mod rules_async;
61mod validatable;
62mod validator;
63
64pub use async_rule::AsyncRule;
65pub use async_validator::{AsyncValidationError, AsyncValidator};
66pub(crate) use bridge::translate_validation;
67pub use bridge::{register_validation_translator, TranslatorFn};
68pub use constraint_map::{ConstraintMap, MapConstraintExt};
69pub use error::ValidationError;
70pub use rule::Rule;
71pub use rules::*;
72pub use rules_async::unique;
73pub use validatable::Validatable;
74pub use validator::{validate, Validator};
75
76/// Macro for creating a vector of boxed validation rules.
77///
78/// This macro boxes each rule, allowing different rule types to be stored
79/// together in a single vector.
80///
81/// # Example
82///
83/// ```rust,ignore
84/// use ferro_rs::validation::{Validator, rules::*};
85/// use ferro_rs::rules;
86///
87/// let validator = Validator::new(&data)
88/// .rules("email", rules![required(), email()])
89/// .rules("name", rules![required(), string(), max(255)]);
90/// ```
91#[macro_export]
92macro_rules! rules {
93 ($($rule:expr),* $(,)?) => {
94 vec![$(Box::new($rule) as Box<dyn $crate::validation::Rule>),*]
95 };
96}