• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Types and traits for extracting data from requests.
2 //!
3 //! See [`axum::extract`] for more details.
4 //!
5 //! [`axum::extract`]: https://docs.rs/axum/latest/axum/extract/index.html
6 
7 use crate::response::IntoResponse;
8 use async_trait::async_trait;
9 use http::{request::Parts, Request};
10 use std::convert::Infallible;
11 
12 pub mod rejection;
13 
14 mod default_body_limit;
15 mod from_ref;
16 mod request_parts;
17 mod tuple;
18 
19 pub(crate) use self::default_body_limit::DefaultBodyLimitKind;
20 pub use self::{default_body_limit::DefaultBodyLimit, from_ref::FromRef};
21 
22 mod private {
23     #[derive(Debug, Clone, Copy)]
24     pub enum ViaParts {}
25 
26     #[derive(Debug, Clone, Copy)]
27     pub enum ViaRequest {}
28 }
29 
30 /// Types that can be created from request parts.
31 ///
32 /// Extractors that implement `FromRequestParts` cannot consume the request body and can thus be
33 /// run in any order for handlers.
34 ///
35 /// If your extractor needs to consume the request body then you should implement [`FromRequest`]
36 /// and not [`FromRequestParts`].
37 ///
38 /// See [`axum::extract`] for more general docs about extractors.
39 ///
40 /// [`axum::extract`]: https://docs.rs/axum/0.6.0/axum/extract/index.html
41 #[async_trait]
42 #[cfg_attr(
43     nightly_error_messages,
44     rustc_on_unimplemented(
45         note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/latest/axum/extract/index.html` for details",
46     )
47 )]
48 pub trait FromRequestParts<S>: Sized {
49     /// If the extractor fails it'll use this "rejection" type. A rejection is
50     /// a kind of error that can be converted into a response.
51     type Rejection: IntoResponse;
52 
53     /// Perform the extraction.
from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection>54     async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection>;
55 }
56 
57 /// Types that can be created from requests.
58 ///
59 /// Extractors that implement `FromRequest` can consume the request body and can thus only be run
60 /// once for handlers.
61 ///
62 /// If your extractor doesn't need to consume the request body then you should implement
63 /// [`FromRequestParts`] and not [`FromRequest`].
64 ///
65 /// See [`axum::extract`] for more general docs about extractors.
66 ///
67 /// # What is the `B` type parameter?
68 ///
69 /// `FromRequest` is generic over the request body (the `B` in
70 /// [`http::Request<B>`]). This is to allow `FromRequest` to be usable with any
71 /// type of request body. This is necessary because some middleware change the
72 /// request body, for example to add timeouts.
73 ///
74 /// If you're writing your own `FromRequest` that wont be used outside your
75 /// application, and not using any middleware that changes the request body, you
76 /// can most likely use `axum::body::Body`.
77 ///
78 /// If you're writing a library that's intended for others to use, it's recommended
79 /// to keep the generic type parameter:
80 ///
81 /// ```rust
82 /// use axum::{
83 ///     async_trait,
84 ///     extract::FromRequest,
85 ///     http::{self, Request},
86 /// };
87 ///
88 /// struct MyExtractor;
89 ///
90 /// #[async_trait]
91 /// impl<S, B> FromRequest<S, B> for MyExtractor
92 /// where
93 ///     // these bounds are required by `async_trait`
94 ///     B: Send + 'static,
95 ///     S: Send + Sync,
96 /// {
97 ///     type Rejection = http::StatusCode;
98 ///
99 ///     async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
100 ///         // ...
101 ///         # unimplemented!()
102 ///     }
103 /// }
104 /// ```
105 ///
106 /// This ensures your extractor is as flexible as possible.
107 ///
108 /// [`http::Request<B>`]: http::Request
109 /// [`axum::extract`]: https://docs.rs/axum/0.6.0/axum/extract/index.html
110 #[async_trait]
111 #[cfg_attr(
112     nightly_error_messages,
113     rustc_on_unimplemented(
114         note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/latest/axum/extract/index.html` for details",
115     )
116 )]
117 pub trait FromRequest<S, B, M = private::ViaRequest>: Sized {
118     /// If the extractor fails it'll use this "rejection" type. A rejection is
119     /// a kind of error that can be converted into a response.
120     type Rejection: IntoResponse;
121 
122     /// Perform the extraction.
from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection>123     async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection>;
124 }
125 
126 #[async_trait]
127 impl<S, B, T> FromRequest<S, B, private::ViaParts> for T
128 where
129     B: Send + 'static,
130     S: Send + Sync,
131     T: FromRequestParts<S>,
132 {
133     type Rejection = <Self as FromRequestParts<S>>::Rejection;
134 
from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection>135     async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
136         let (mut parts, _) = req.into_parts();
137         Self::from_request_parts(&mut parts, state).await
138     }
139 }
140 
141 #[async_trait]
142 impl<S, T> FromRequestParts<S> for Option<T>
143 where
144     T: FromRequestParts<S>,
145     S: Send + Sync,
146 {
147     type Rejection = Infallible;
148 
from_request_parts( parts: &mut Parts, state: &S, ) -> Result<Option<T>, Self::Rejection>149     async fn from_request_parts(
150         parts: &mut Parts,
151         state: &S,
152     ) -> Result<Option<T>, Self::Rejection> {
153         Ok(T::from_request_parts(parts, state).await.ok())
154     }
155 }
156 
157 #[async_trait]
158 impl<S, T, B> FromRequest<S, B> for Option<T>
159 where
160     T: FromRequest<S, B>,
161     B: Send + 'static,
162     S: Send + Sync,
163 {
164     type Rejection = Infallible;
165 
from_request(req: Request<B>, state: &S) -> Result<Option<T>, Self::Rejection>166     async fn from_request(req: Request<B>, state: &S) -> Result<Option<T>, Self::Rejection> {
167         Ok(T::from_request(req, state).await.ok())
168     }
169 }
170 
171 #[async_trait]
172 impl<S, T> FromRequestParts<S> for Result<T, T::Rejection>
173 where
174     T: FromRequestParts<S>,
175     S: Send + Sync,
176 {
177     type Rejection = Infallible;
178 
from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection>179     async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
180         Ok(T::from_request_parts(parts, state).await)
181     }
182 }
183 
184 #[async_trait]
185 impl<S, T, B> FromRequest<S, B> for Result<T, T::Rejection>
186 where
187     T: FromRequest<S, B>,
188     B: Send + 'static,
189     S: Send + Sync,
190 {
191     type Rejection = Infallible;
192 
from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection>193     async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
194         Ok(T::from_request(req, state).await)
195     }
196 }
197