actix_web/
handler.rs

1use std::future::Future;
2
3use actix_service::{boxed, fn_service};
4
5use crate::{
6    service::{BoxedHttpServiceFactory, ServiceRequest, ServiceResponse},
7    FromRequest, HttpResponse, Responder,
8};
9
10/// The interface for request handlers.
11///
12/// # What Is A Request Handler
13///
14/// In short, a handler is just an async function that receives request-based arguments, in any
15/// order, and returns something that can be converted to a response.
16///
17/// In particular, a request handler has three requirements:
18///
19/// 1. It is an async function (or a function/closure that returns an appropriate future);
20/// 1. The function parameters (up to 12) implement [`FromRequest`];
21/// 1. The async function (or future) resolves to a type that can be converted into an
22///    [`HttpResponse`] (i.e., it implements the [`Responder`] trait).
23///
24///
25/// # Compiler Errors
26///
27/// If you get the error `the trait Handler<_> is not implemented`, then your handler does not
28/// fulfill the _first_ of the above requirements. (It could also mean that you're attempting to use
29/// a macro-routed handler in a manual routing context like `web::get().to(handler)`, which is not
30/// supported). Breaking the other requirements manifests as errors on implementing [`FromRequest`]
31/// and [`Responder`], respectively.
32///
33/// # How Do Handlers Receive Variable Numbers Of Arguments
34///
35/// Rest assured there is no macro magic here; it's just traits.
36///
37/// The first thing to note is that [`FromRequest`] is implemented for tuples (up to 12 in length).
38///
39/// Secondly, the `Handler` trait is implemented for functions (up to an [arity] of 12) in a way
40/// that aligns their parameter positions with a corresponding tuple of types (becoming the `Args`
41/// type parameter for this trait).
42///
43/// Thanks to Rust's type system, Actix Web can infer the function parameter types. During the
44/// extraction step, the parameter types are described as a tuple type, [`from_request`] is run on
45/// that tuple, and the `Handler::call` implementation for that particular function arity
46/// destructures the tuple into its component types and calls your handler function with them.
47///
48/// In pseudo-code the process looks something like this:
49///
50/// ```ignore
51/// async fn my_handler(body: String, state: web::Data<MyState>) -> impl Responder {
52///     ...
53/// }
54///
55/// // the function params above described as a tuple, names do not matter, only position
56/// type InferredMyHandlerArgs = (String, web::Data<MyState>);
57///
58/// // create tuple of arguments to be passed to handler
59/// let args = InferredMyHandlerArgs::from_request(&request, &payload).await;
60///
61/// // call handler with argument tuple
62/// let response = Handler::call(&my_handler, args).await;
63///
64/// // which is effectively...
65///
66/// let (body, state) = args;
67/// let response = my_handler(body, state).await;
68/// ```
69///
70/// This is the source code for the 2-parameter implementation of `Handler` to help illustrate the
71/// bounds of the handler call after argument extraction:
72/// ```ignore
73/// impl<Func, Arg1, Arg2, Fut> Handler<(Arg1, Arg2)> for Func
74/// where
75///     Func: Fn(Arg1, Arg2) -> Fut + Clone + 'static,
76///     Fut: Future,
77/// {
78///     type Output = Fut::Output;
79///     type Future = Fut;
80///
81///     fn call(&self, (arg1, arg2): (Arg1, Arg2)) -> Self::Future {
82///         (self)(arg1, arg2)
83///     }
84/// }
85/// ```
86///
87/// [arity]: https://en.wikipedia.org/wiki/Arity
88/// [`from_request`]: FromRequest::from_request
89pub trait Handler<Args>: Clone + 'static {
90    type Output;
91    type Future: Future<Output = Self::Output>;
92
93    fn call(&self, args: Args) -> Self::Future;
94}
95
96pub(crate) fn handler_service<F, Args>(handler: F) -> BoxedHttpServiceFactory
97where
98    F: Handler<Args>,
99    Args: FromRequest,
100    F::Output: Responder,
101{
102    boxed::factory(fn_service(move |req: ServiceRequest| {
103        let handler = handler.clone();
104
105        async move {
106            let (req, mut payload) = req.into_parts();
107
108            let res = match Args::from_request(&req, &mut payload).await {
109                Err(err) => HttpResponse::from_error(err),
110
111                Ok(data) => handler
112                    .call(data)
113                    .await
114                    .respond_to(&req)
115                    .map_into_boxed_body(),
116            };
117
118            Ok(ServiceResponse::new(req, res))
119        }
120    }))
121}
122
123/// Generates a [`Handler`] trait impl for N-ary functions where N is specified with a sequence of
124/// space separated type parameters.
125///
126/// # Examples
127/// ```ignore
128/// factory_tuple! {}         // implements Handler for types: fn() -> R
129/// factory_tuple! { A B C }  // implements Handler for types: fn(A, B, C) -> R
130/// ```
131macro_rules! factory_tuple ({ $($param:ident)* } => {
132    impl<Func, Fut, $($param,)*> Handler<($($param,)*)> for Func
133    where
134        Func: Fn($($param),*) -> Fut + Clone + 'static,
135        Fut: Future,
136    {
137        type Output = Fut::Output;
138        type Future = Fut;
139
140        #[inline]
141        #[allow(non_snake_case)]
142        fn call(&self, ($($param,)*): ($($param,)*)) -> Self::Future {
143            (self)($($param,)*)
144        }
145    }
146});
147
148factory_tuple! {}
149factory_tuple! { A }
150factory_tuple! { A B }
151factory_tuple! { A B C }
152factory_tuple! { A B C D }
153factory_tuple! { A B C D E }
154factory_tuple! { A B C D E F }
155factory_tuple! { A B C D E F G }
156factory_tuple! { A B C D E F G H }
157factory_tuple! { A B C D E F G H I }
158factory_tuple! { A B C D E F G H I J }
159factory_tuple! { A B C D E F G H I J K }
160factory_tuple! { A B C D E F G H I J K L }
161factory_tuple! { A B C D E F G H I J K L M }
162factory_tuple! { A B C D E F G H I J K L M N }
163factory_tuple! { A B C D E F G H I J K L M N O }
164factory_tuple! { A B C D E F G H I J K L M N O P }
165
166#[cfg(test)]
167mod tests {
168    use super::*;
169
170    fn assert_impl_handler<T: FromRequest>(_: impl Handler<T>) {}
171
172    #[test]
173    fn arg_number() {
174        async fn handler_min() {}
175
176        #[rustfmt::skip]
177        #[allow(clippy::too_many_arguments, clippy::just_underscores_and_digits, clippy::let_unit_value)]
178        async fn handler_max(
179            _01: (), _02: (), _03: (), _04: (), _05: (), _06: (),
180            _07: (), _08: (), _09: (), _10: (), _11: (), _12: (),
181            _13: (), _14: (), _15: (), _16: (),
182        ) {}
183
184        assert_impl_handler(handler_min);
185        assert_impl_handler(handler_max);
186    }
187}