use axum::extract::{FromRequest, Request}; use axum_extra::extract::Form; use serde::de::DeserializeOwned; use validator::Validate; use crate::errors::{AppError, bad_request}; /// Wrapper around [`axum_extra::extract::Form`] which returns an /// [`AppError::BadRequest`] if [`validator`] checks on the target type do not /// pass. #[derive(Debug, Clone, Copy, Default)] pub(crate) struct ValidatedForm(pub(crate) T); impl FromRequest for ValidatedForm where T: DeserializeOwned + Validate, S: Send + Sync, { type Rejection = AppError; async fn from_request(req: Request, state: &S) -> Result { let Form(form) = Form::::from_request(req, state) .await .map_err(|err| bad_request!("couldn't parse form: {err}"))?; form.validate() .map_err(|err| bad_request!("couldn't validate form: {err}"))?; Ok(ValidatedForm(form)) } }