use crate::errors::{ErrorCode, ErrorResponse};
use axum::{
extract::{FromRequest, Json, Request},
http::StatusCode,
response::{IntoResponse, Response},
};
use serde::de::DeserializeOwned;
use validator::Validate;
pub struct ValidatedJson<T>(pub T);
impl<T, S> FromRequest<S> for ValidatedJson<T>
where
T: DeserializeOwned + Validate,
S: Send + Sync,
{
type Rejection = Response;
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
let Json(data) = Json::<T>::from_request(req, state)
.await
.map_err(|e| e.into_response())?;
data.validate().map_err(|e| {
let details = e
.field_errors()
.iter()
.map(|(field, errors)| {
let error_messages: Vec<serde_json::Value> = errors
.iter()
.map(|err| {
serde_json::json!({
"code": err.code,
"message": err.message,
"params": err.params,
})
})
.collect();
(field.to_string(), serde_json::json!(error_messages))
})
.collect::<serde_json::Map<_, _>>();
let error_response = ErrorResponse {
code: ErrorCode::ValidationError.code(),
error: ErrorCode::ValidationError.as_str().to_string(),
message: ErrorCode::ValidationError.default_message().to_string(),
details: Some(serde_json::Value::Object(details)),
};
(StatusCode::BAD_REQUEST, axum::Json(error_response)).into_response()
})?;
Ok(ValidatedJson(data))
}
}