Skip to main content

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}