use crate::validation::validators::ValidationError;
use std::fmt::{Display, Formatter};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GardeError {
pub fields: Vec<ValidationError>,
}
impl Display for GardeError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "validation failed: {}",
self.fields.iter()
.map(|e| format!("{}: {}", e.field, e.message))
.collect::<Vec<_>>()
.join("; ")
)
}
}
pub fn validate<T>(value: &T) -> Result<(), Vec<ValidationError>>
where
T: garde::Validate,
<T as garde::Validate>::Context: Default,
{
match value.validate() {
Ok(()) => Ok(()),
Err(report) => {
let errors: Vec<ValidationError> = report
.iter()
.map(|item| {
let (path, error) = item;
let field = path.to_string();
ValidationError::new(&field, error.message())
})
.collect();
Err(errors)
}
}
}
pub fn validate_or_raise<T>(value: T) -> crate::Result<T>
where
T: garde::Validate + Clone,
<T as garde::Validate>::Context: Default,
{
match value.validate() {
Ok(()) => Ok(value),
Err(report) => {
let errors: Vec<ValidationError> = report
.iter()
.map(|item| {
let (path, error) = item;
let field = path.to_string();
ValidationError::new(&field, error.message())
})
.collect();
Err(crate::AppError::validation_report(errors))
}
}
}
pub use garde::Validate;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validation_error_display() {
let err = GardeError {
fields: vec![
ValidationError::new("email", "must be a valid email"),
ValidationError::new("name", "too short"),
],
};
let display = format!("{}", err);
assert!(display.contains("email"));
assert!(display.contains("name"));
}
}