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;
11
12#[derive(Clone, Debug)]
13pub(crate) struct JsonRejectionCode(pub(crate) String);
14
15#[derive(Clone, Copy, Debug, Default)]
20pub struct ApiJson<T>(
21 pub T,
23);
24
25impl<T, S> FromRequest<S> for ApiJson<T>
26where
27 T: DeserializeOwned,
28 S: Send + Sync,
29{
30 type Rejection = ApiError;
31
32 async fn from_request(request: Request, state: &S) -> Result<Self, Self::Rejection> {
33 let rejection_code = request
34 .extensions()
35 .get::<JsonRejectionCode>()
36 .map_or("validation_failed", |code| code.0.as_str())
37 .to_owned();
38 Json::<T>::from_request(request, state)
39 .await
40 .map(|Json(value)| Self(value))
41 .map_err(|_| ApiError::json_rejection(rejection_code))
42 }
43}
44
45impl<T> Deref for ApiJson<T> {
46 type Target = T;
47
48 fn deref(&self) -> &Self::Target {
49 &self.0
50 }
51}
52
53impl<T> DerefMut for ApiJson<T> {
54 fn deref_mut(&mut self) -> &mut Self::Target {
55 &mut self.0
56 }
57}
58
59#[derive(Clone, Copy, Debug, Default)]
64pub struct Path<T>(
65 pub T,
67);
68
69impl<T, S> FromRequestParts<S> for Path<T>
70where
71 T: DeserializeOwned + Send,
72 S: Send + Sync,
73{
74 type Rejection = ApiError;
75
76 async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
77 AxumPath::<T>::from_request_parts(parts, state)
78 .await
79 .map(|AxumPath(value)| Self(value))
80 .map_err(ApiError::from)
81 }
82}
83
84impl<T> Deref for Path<T> {
85 type Target = T;
86
87 fn deref(&self) -> &Self::Target {
88 &self.0
89 }
90}
91
92impl<T> DerefMut for Path<T> {
93 fn deref_mut(&mut self) -> &mut Self::Target {
94 &mut self.0
95 }
96}
97
98pub use Path as ApiPath;
100
101#[derive(Clone, Copy, Debug, Default)]
110pub struct Query<T>(
111 pub T,
113);
114
115impl<T, S> FromRequestParts<S> for Query<T>
116where
117 T: DeserializeOwned,
118 S: Send + Sync,
119{
120 type Rejection = ApiError;
121
122 async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
123 serde_html_form::from_str(parts.uri.query().unwrap_or_default())
124 .map(Self)
125 .map_err(|_| ApiError::query_rejection())
126 }
127}
128
129impl<T> Deref for Query<T> {
130 type Target = T;
131
132 fn deref(&self) -> &Self::Target {
133 &self.0
134 }
135}
136
137impl<T> DerefMut for Query<T> {
138 fn deref_mut(&mut self) -> &mut Self::Target {
139 &mut self.0
140 }
141}
142
143pub use Query as ApiQuery;