1use std::ops::{Deref, DerefMut};
2
3use axum::{
4 Json,
5 extract::{FromRequest, FromRequestParts, Path as AxumPath, Request},
6 http::request::Parts,
7};
8use serde::de::DeserializeOwned;
9
10use crate::{ApiError, options::JsonRejectionMode};
11
12#[derive(Clone, Copy, Debug, Default)]
18pub struct ApiJson<T>(
19 pub T,
21);
22
23impl<T, S> FromRequest<S> for ApiJson<T>
24where
25 T: DeserializeOwned,
26 S: Send + Sync,
27{
28 type Rejection = ApiError;
29
30 async fn from_request(request: Request, state: &S) -> Result<Self, Self::Rejection> {
31 let rejection_mode = request
32 .extensions()
33 .get::<JsonRejectionMode>()
34 .cloned()
35 .unwrap_or_else(|| JsonRejectionMode::Legacy("validation_failed".to_owned()));
36 Json::<T>::from_request(request, state)
37 .await
38 .map(|Json(value)| Self(value))
39 .map_err(|rejection| ApiError::json_rejection(&rejection, &rejection_mode))
40 }
41}
42
43impl<T> Deref for ApiJson<T> {
44 type Target = T;
45
46 fn deref(&self) -> &Self::Target {
47 &self.0
48 }
49}
50
51impl<T> DerefMut for ApiJson<T> {
52 fn deref_mut(&mut self) -> &mut Self::Target {
53 &mut self.0
54 }
55}
56
57#[derive(Clone, Copy, Debug, Default)]
62pub struct Path<T>(
63 pub T,
65);
66
67impl<T, S> FromRequestParts<S> for Path<T>
68where
69 T: DeserializeOwned + Send,
70 S: Send + Sync,
71{
72 type Rejection = ApiError;
73
74 async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
75 AxumPath::<T>::from_request_parts(parts, state)
76 .await
77 .map(|AxumPath(value)| Self(value))
78 .map_err(ApiError::from)
79 }
80}
81
82impl<T> Deref for Path<T> {
83 type Target = T;
84
85 fn deref(&self) -> &Self::Target {
86 &self.0
87 }
88}
89
90impl<T> DerefMut for Path<T> {
91 fn deref_mut(&mut self) -> &mut Self::Target {
92 &mut self.0
93 }
94}
95
96pub use Path as ApiPath;
98
99#[derive(Clone, Copy, Debug, Default)]
108pub struct Query<T>(
109 pub T,
111);
112
113impl<T, S> FromRequestParts<S> for Query<T>
114where
115 T: DeserializeOwned,
116 S: Send + Sync,
117{
118 type Rejection = ApiError;
119
120 async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
121 serde_html_form::from_str(parts.uri.query().unwrap_or_default())
122 .map(Self)
123 .map_err(|_| ApiError::query_rejection())
124 }
125}
126
127impl<T> Deref for Query<T> {
128 type Target = T;
129
130 fn deref(&self) -> &Self::Target {
131 &self.0
132 }
133}
134
135impl<T> DerefMut for Query<T> {
136 fn deref_mut(&mut self) -> &mut Self::Target {
137 &mut self.0
138 }
139}
140
141pub use Query as ApiQuery;