Skip to main content

px_validation/
lib.rs

1use axum::body::Bytes;
2use axum::extract::FromRequest;
3use axum::http::Request;
4use px_errors::AppError;
5use serde::de::DeserializeOwned;
6
7pub trait Validate {
8    fn validate(&self) -> Result<(), String>;
9}
10
11#[derive(Debug)]
12pub struct Validated<T>(pub T);
13
14impl<T, S> FromRequest<S> for Validated<T>
15where
16    T: DeserializeOwned + Validate + 'static,
17    S: Send + Sync,
18{
19    type Rejection = AppError;
20
21    async fn from_request(req: Request<axum::body::Body>, state: &S) -> Result<Self, AppError> {
22        let bytes = Bytes::from_request(req, state)
23            .await
24            .map_err(|e| AppError::BadRequest(format!("body read failed: {e}")))?;
25        let value: T = serde_json::from_slice(&bytes)
26            .map_err(|e| AppError::BadRequest(format!("invalid JSON: {e}")))?;
27        value.validate().map_err(AppError::ValidationError)?;
28        Ok(Validated(value))
29    }
30}