armature_validation/
pipe.rs1use crate::{Validate, ValidationErrors};
4use armature_core::{Error, HttpRequest, HttpResponse};
5use serde::de::DeserializeOwned;
6
7pub struct ValidationPipe;
9
10impl ValidationPipe {
11 pub fn parse<T>(req: &HttpRequest) -> Result<T, Error>
13 where
14 T: DeserializeOwned + Validate,
15 {
16 let parsed: T = serde_json::from_slice(&req.body)
18 .map_err(|e| Error::BadRequest(format!("Invalid JSON: {}", e)))?;
19
20 parsed
22 .validate()
23 .map_err(|errors| Error::BadRequest(format!("Validation failed: {:?}", errors)))?;
24
25 Ok(parsed)
26 }
27
28 pub fn error_response(errors: ValidationErrors) -> HttpResponse {
30 HttpResponse::from_parts(
31 400,
32 std::collections::HashMap::from([(
33 "Content-Type".to_string(),
34 "application/json".to_string(),
35 )]),
36 errors.to_json().to_string().into_bytes(),
37 )
38 }
39}
40
41#[macro_export]
43macro_rules! validate {
44 ($dto:expr) => {{
45 $dto.validate()
46 .map_err(|errors| armature_core::Error::BadRequest(format!("{:?}", errors)))?
47 }};
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use crate::{Validate, ValidationError};
54 use serde::{Deserialize, Serialize};
55
56 #[derive(Debug, Deserialize, Serialize)]
57 struct TestDto {
58 name: String,
59 age: i32,
60 }
61
62 impl Validate for TestDto {
63 fn validate(&self) -> Result<(), Vec<ValidationError>> {
64 let mut errors = Vec::new();
65
66 if self.name.is_empty() {
67 errors.push(ValidationError::new("name", "Name is required"));
68 }
69
70 if self.age < 0 {
71 errors.push(ValidationError::new("age", "Age must be positive"));
72 }
73
74 if errors.is_empty() {
75 Ok(())
76 } else {
77 Err(errors)
78 }
79 }
80 }
81
82 #[test]
83 fn test_validation_pipe() {
84 let valid_dto = TestDto {
85 name: "John".to_string(),
86 age: 30,
87 };
88
89 let json = serde_json::to_vec(&valid_dto).unwrap();
90 let mut req = HttpRequest::new("POST".to_string(), "/test".to_string());
91 req.body = json;
92
93 let result: Result<TestDto, Error> = ValidationPipe::parse(&req);
94 assert!(result.is_ok());
95 }
96}