kegani 0.1.1

A developer-friendly, ergonomic, production-ready Rust web framework
Documentation
//! Validation extractors for Kegani
//!
//! Provides `ValidatedForm<T>` and `ValidatedQuery<T>` extractors.
//!
//! Note: For JSON body extraction, use `actix_web::web::Json<T>` directly.
//! For validated form/query extraction, use the types here with your own validation logic.

use crate::validation::validators::ValidationError;

/// Validated form extractor marker.
///
/// This struct wraps a parsed form value. Apply your own validation
/// in the handler.
///
/// # Example
/// ```ignore
/// async fn create_user(
///     ValidatedForm(payload): ValidatedForm<CreateUser>,
/// ) -> Result<Json<User>, AppError> {
///     // payload is parsed; apply validation before use
///     if payload.email.is_empty() {
///         return Err(AppError::validation("email cannot be empty"));
///     }
///     // ...
/// }
/// ```
#[derive(Debug)]
pub struct ValidatedForm<T>(pub T);

/// Validated query extractor marker.
///
/// This struct wraps parsed query parameters. Apply your own validation
/// in the handler.
///
/// # Example
/// ```ignore
/// async fn list_users(
///     ValidatedQuery(params): ValidatedQuery<Pagination>,
/// ) -> Result<Json<Vec<User>>, AppError> {
///     // params.page, params.size
/// }
/// ```
#[derive(Debug)]
pub struct ValidatedQuery<T>(pub T);

/// Trait for types that implement their own validation logic
///
/// Implement `Validate` on your DTO to enable structured field-level validation.
///
/// # Example
/// ```ignore
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// pub struct CreateUser {
///     pub email: String,
///     pub password: String,
/// }
///
/// impl Validate for CreateUser {
///     fn validate(self) -> Result<Self, Vec<ValidationError>> {
///         let mut errors = Vec::new();
///         if !self.email.contains('@') {
///             errors.push(ValidationError::new("email", "Must be a valid email"));
///         }
///         if self.password.len() < 8 {
///             errors.push(ValidationError::new("password", "Must be at least 8 characters"));
///         }
///         if errors.is_empty() { Ok(self) } else { Err(errors) }
///     }
/// }
/// ```
pub trait Validate: Sized {
    /// Validate the data, returning self on success or a list of errors on failure
    fn validate(self) -> Result<Self, Vec<ValidationError>>;
}