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}