#[cfg(feature = "validation")]
use crate::error::AppError;
#[cfg(feature = "validation")]
use crate::extractor::from_request::{FRFut, FromRequest};
#[cfg(feature = "validation")]
use crate::handler::Req;
#[cfg(feature = "validation")]
use http_body_util::BodyExt;
#[cfg(feature = "validation")]
use serde::de::DeserializeOwned;
#[cfg(feature = "validation")]
use std::sync::Arc;
#[cfg(feature = "validation")]
#[derive(Debug)]
pub struct ValidatedJson<T>(pub T);
#[cfg(feature = "validation")]
impl<S, T> FromRequest<S> for ValidatedJson<T>
where
T: DeserializeOwned + garde::Validate + Send + Sync + 'static,
<T as garde::Validate>::Context: Default,
S: Send + Sync + 'static,
{
fn from_request(mut req: Req, _state: Arc<S>) -> FRFut<Self> {
Box::pin(async move {
let body = req
.body_mut()
.collect()
.await
.map_err(|e| AppError::BadRequest(format!("Failed to read request body: {}", e)))?
.to_bytes();
let value: T = serde_json::from_slice(&body).map_err(AppError::JsonParseError)?;
value.validate().map_err(AppError::from)?;
Ok(ValidatedJson(value))
})
}
}
#[cfg(feature = "validation")]
impl<T> std::ops::Deref for ValidatedJson<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "validation")]
impl<T> std::ops::DerefMut for ValidatedJson<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}