rustapi_validate/
lib.rs

1//! # RustAPI Validation
2//!
3//! Validation system for RustAPI framework. Provides declarative validation
4//! on structs using the `#[derive(Validate)]` macro.
5//!
6//! ## Example
7//!
8//! ```rust,ignore
9//! use rustapi_validate::prelude::*;
10//! use validator::Validate;
11//!
12//! #[derive(Validate)]
13//! struct CreateUser {
14//!     #[validate(email)]
15//!     email: String,
16//!     
17//!     #[validate(length(min = 3, max = 50))]
18//!     username: String,
19//!     
20//!     #[validate(range(min = 18, max = 120))]
21//!     age: u8,
22//! }
23//! ```
24//!
25//! ## V2 Validation Engine
26//!
27//! The v2 module provides a custom validation engine with async support:
28//!
29//! ```rust,ignore
30//! use rustapi_validate::v2::prelude::*;
31//!
32//! #[derive(Validate)]
33//! struct CreateUser {
34//!     #[validate(email, message = "Invalid email format")]
35//!     email: String,
36//!     
37//!     #[validate(length(min = 3, max = 50))]
38//!     username: String,
39//!     
40//!     #[validate(async_unique(table = "users", column = "email"))]
41//!     unique_email: String,
42//! }
43//! ```
44//!
45//! ## Validation Rules
46//!
47//! - `email` - Validates email format
48//! - `length(min = X, max = Y)` - String length validation
49//! - `range(min = X, max = Y)` - Numeric range validation
50//! - `regex = "..."` - Regex pattern validation
51//! - `url` - URL format validation
52//! - `required` - Non-empty string/option validation
53//! - `async_unique(table, column)` - Database uniqueness check
54//! - `async_exists(table, column)` - Database existence check
55//! - `async_api(endpoint)` - External API validation
56//!
57//! ## Error Format
58//!
59//! Validation errors return a 422 Unprocessable Entity with JSON:
60//!
61//! ```json
62//! {
63//!   "error": {
64//!     "type": "validation_error",
65//!     "message": "Validation failed",
66//!     "fields": [
67//!       {"field": "email", "code": "email", "message": "Invalid email format"},
68//!       {"field": "age", "code": "range", "message": "Value must be between 18 and 120"}
69//!     ]
70//!   }
71//! }
72//! ```
73
74pub mod custom;
75mod error;
76mod validate;
77
78/// V2 validation engine with async support.
79///
80/// This module provides a custom validation engine that replaces the external
81/// `validator` dependency and adds support for async validation operations.
82pub mod v2;
83
84pub use error::{FieldError, ValidationError};
85pub use validate::Validate;
86
87// Re-export the derive macro from validator (wrapped)
88// In a full implementation, we'd create our own proc-macro
89// For now, we use validator's derive with our own trait
90pub use validator::Validate as ValidatorValidate;
91
92// Re-export the v2 Validate derive macro
93pub use rustapi_macros::Validate as DeriveValidate;
94
95/// Prelude module for validation
96pub mod prelude {
97    pub use crate::error::{FieldError, ValidationError};
98    pub use crate::validate::Validate;
99    pub use validator::Validate as ValidatorValidate;
100
101    // Re-export v2 prelude
102    pub use crate::v2::prelude::*;
103
104    // Re-export derive macro
105    pub use rustapi_macros::Validate as DeriveValidate;
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn validation_error_to_json() {
114        let error = ValidationError::new(vec![
115            FieldError::new("email", "email", "Invalid email format"),
116            FieldError::new("age", "range", "Value must be between 18 and 120"),
117        ]);
118
119        let json = serde_json::to_string_pretty(&error).unwrap();
120        assert!(json.contains("validation_error"));
121        assert!(json.contains("email"));
122        assert!(json.contains("age"));
123    }
124}