use axum::extract::{Form, FromRequest, FromRequestParts, Json, Path, Query};
use axum::response::{IntoResponse, Response};
use serde::de::DeserializeOwned;
use crate::validation::errors::validation_problem;
use crate::validation::rejection::{
from_form_rejection, from_json_rejection, from_path_rejection, from_query_rejection,
};
pub struct ValidatedJson<T>(pub T);
pub struct ValidatedForm<T>(pub T);
pub struct ValidatedQuery<T>(pub T);
pub struct ValidatedPath<T>(pub T);
impl<T> ValidatedJson<T> {
#[must_use]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> ValidatedForm<T> {
#[must_use]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> ValidatedQuery<T> {
#[must_use]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> ValidatedPath<T> {
#[must_use]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T, S> FromRequest<S> for ValidatedJson<T>
where
T: DeserializeOwned + validator::Validate,
S: Send + Sync,
{
type Rejection = Response;
async fn from_request(req: axum::extract::Request, state: &S) -> Result<Self, Self::Rejection> {
let Json(value) = Json::<T>::from_request(req, state)
.await
.map_err(|rejection| from_json_rejection(&rejection).into_response())?;
match validator::Validate::validate(&value) {
Ok(()) => Ok(ValidatedJson(value)),
Err(errors) => Err(validation_problem(errors).into_response()),
}
}
}
impl<T, S> FromRequest<S> for ValidatedForm<T>
where
T: DeserializeOwned + validator::Validate,
S: Send + Sync,
{
type Rejection = Response;
async fn from_request(req: axum::extract::Request, state: &S) -> Result<Self, Self::Rejection> {
let Form(value) = Form::<T>::from_request(req, state)
.await
.map_err(|rejection| from_form_rejection(&rejection).into_response())?;
match validator::Validate::validate(&value) {
Ok(()) => Ok(ValidatedForm(value)),
Err(errors) => Err(validation_problem(errors).into_response()),
}
}
}
impl<T, S> FromRequestParts<S> for ValidatedQuery<T>
where
T: DeserializeOwned + validator::Validate,
S: Send + Sync,
{
type Rejection = Response;
async fn from_request_parts(
parts: &mut axum::http::request::Parts,
state: &S,
) -> Result<Self, Self::Rejection> {
let Query(value) = Query::<T>::from_request_parts(parts, state)
.await
.map_err(|rejection| from_query_rejection(&rejection).into_response())?;
match validator::Validate::validate(&value) {
Ok(()) => Ok(ValidatedQuery(value)),
Err(errors) => Err(validation_problem(errors).into_response()),
}
}
}
impl<T, S> FromRequestParts<S> for ValidatedPath<T>
where
T: DeserializeOwned + Send + Sync + validator::Validate,
S: Send + Sync,
{
type Rejection = Response;
async fn from_request_parts(
parts: &mut axum::http::request::Parts,
state: &S,
) -> Result<Self, Self::Rejection> {
let Path(value) = Path::<T>::from_request_parts(parts, state)
.await
.map_err(|rejection| from_path_rejection(&rejection).into_response())?;
match validator::Validate::validate(&value) {
Ok(()) => Ok(ValidatedPath(value)),
Err(errors) => Err(validation_problem(errors).into_response()),
}
}
}