Skip to main content

nestforge_core/
request.rs

1use std::ops::Deref;
2
3use axum::{
4    extract::{FromRequest, FromRequestParts, Path},
5    http::request::Parts,
6};
7use serde::de::DeserializeOwned;
8
9use crate::HttpException;
10
11/*
12Param<T> = path param wrapper
13
14User writes:
15id: Param<u64>
16
17Instead of:
18Path(id): Path<u64>
19*/
20pub struct Param<T>(pub T);
21
22impl<T> Deref for Param<T> {
23    type Target = T;
24
25    fn deref(&self) -> &Self::Target {
26        &self.0
27    }
28}
29
30/*
31Extract Param<T> from route path params.
32*/
33impl<S, T> FromRequestParts<S> for Param<T>
34where
35    S: Send + Sync,
36    T: DeserializeOwned + Send + 'static,
37{
38    type Rejection = HttpException;
39
40    async fn from_request_parts(
41        parts: &mut Parts,
42        state: &S,
43    ) -> Result<Self, Self::Rejection> {
44        let Path(value) = Path::<T>::from_request_parts(parts, state)
45            .await
46            .map_err(|_| HttpException::bad_request("Invalid route parameter"))?;
47
48        Ok(Self(value))
49    }
50}
51
52/*
53Body<T> = JSON request body wrapper
54
55User writes:
56body: Body<CreateUserDto>
57
58Instead of:
59Json(dto): Json<CreateUserDto>
60*/
61pub struct Body<T>(pub T);
62
63impl<T> Deref for Body<T> {
64    type Target = T;
65
66    fn deref(&self) -> &Self::Target {
67        &self.0
68    }
69}
70
71impl<T> Body<T> {
72    pub fn into_inner(self) -> T {
73        self.0
74    }
75}
76
77/*
78Extract Body<T> from JSON request body.
79*/
80impl<S, T> FromRequest<S> for Body<T>
81where
82    S: Send + Sync,
83    T: DeserializeOwned + Send + 'static,
84{
85    type Rejection = HttpException;
86
87    async fn from_request(
88        req: axum::extract::Request,
89        state: &S,
90    ) -> Result<Self, Self::Rejection> {
91        let axum::Json(value) = axum::Json::<T>::from_request(req, state)
92            .await
93            .map_err(|_| HttpException::bad_request("Invalid JSON body"))?;
94
95        Ok(Self(value))
96    }
97}