1use axum::{
10 extract::{FromRequest, Json},
11 response::{IntoResponse, Response},
12};
13use alun_core::api::ApiError;
14use serde::de::DeserializeOwned;
15
16#[derive(Debug, Clone, Copy, Default)]
34pub struct ValidatedJson<T>(pub T);
35
36impl<T, S> FromRequest<S> for ValidatedJson<T>
40where
41 T: DeserializeOwned,
42 S: Send + Sync,
43{
44 type Rejection = ValidatedJsonRejection;
45
46 async fn from_request(req: axum::extract::Request, state: &S) -> Result<Self, Self::Rejection> {
47 match Json::<T>::from_request(req, state).await {
48 Ok(Json(value)) => Ok(ValidatedJson(value)),
49 Err(rejection) => {
50 let msg = format!("请求体格式错误: {}", rejection.body_text());
51 Err(ValidatedJsonRejection(ApiError::bad_request(msg)))
52 }
53 }
54 }
55}
56
57impl<T: validator::Validate> ValidatedJson<T> {
59 pub fn validate(self) -> Result<Self, ApiError> {
63 self.0.validate().map_err(|e| {
64 ApiError::unprocessable_entity(
65 alun_utils::valid::Valid::format_validation_errors(&e)
66 )
67 })?;
68 Ok(self)
69 }
70}
71
72impl<T> std::ops::Deref for ValidatedJson<T> {
73 type Target = T;
74
75 fn deref(&self) -> &Self::Target {
76 &self.0
77 }
78}
79
80impl<T> std::ops::DerefMut for ValidatedJson<T> {
81 fn deref_mut(&mut self) -> &mut Self::Target {
82 &mut self.0
83 }
84}
85
86#[derive(Debug)]
88pub struct ValidatedJsonRejection(pub ApiError);
89
90impl IntoResponse for ValidatedJsonRejection {
91 fn into_response(self) -> Response {
92 self.0.into_response()
93 }
94}
95
96impl From<ValidatedJsonRejection> for ApiError {
97 fn from(rejection: ValidatedJsonRejection) -> Self {
98 rejection.0
99 }
100}