Trait actix_web::Handler

source ·
pub trait Handler<Args>: Clone + 'static {
    type Output;
    type Future: Future<Output = Self::Output>;

    // Required method
    fn call(&self, args: Args) -> Self::Future;
}
Expand description

The interface for request handlers.

What Is A Request Handler

In short, a handler is just an async function that receives request-based arguments, in any order, and returns something that can be converted to a response.

In particular, a request handler has three requirements:

  1. It is an async function (or a function/closure that returns an appropriate future);
  2. The function parameters (up to 12) implement FromRequest;
  3. The async function (or future) resolves to a type that can be converted into an HttpResponse (i.e., it implements the Responder trait).

Compiler Errors

If you get the error the trait Handler<_> is not implemented, then your handler does not fulfill the first of the above requirements. Missing other requirements manifest as errors on implementing FromRequest and Responder, respectively.

How Do Handlers Receive Variable Numbers Of Arguments

Rest assured there is no macro magic here; it’s just traits.

The first thing to note is that FromRequest is implemented for tuples (up to 12 in length).

Secondly, the Handler trait is implemented for functions (up to an arity of 12) in a way that aligns their parameter positions with a corresponding tuple of types (becoming the Args type parameter for this trait).

Thanks to Rust’s type system, Actix Web can infer the function parameter types. During the extraction step, the parameter types are described as a tuple type, from_request is run on that tuple, and the Handler::call implementation for that particular function arity destructures the tuple into its component types and calls your handler function with them.

In pseudo-code the process looks something like this:

async fn my_handler(body: String, state: web::Data<MyState>) -> impl Responder {
    ...
}

// the function params above described as a tuple, names do not matter, only position
type InferredMyHandlerArgs = (String, web::Data<MyState>);

// create tuple of arguments to be passed to handler
let args = InferredMyHandlerArgs::from_request(&request, &payload).await;

// call handler with argument tuple
let response = Handler::call(&my_handler, args).await;

// which is effectively...

let (body, state) = args;
let response = my_handler(body, state).await;

This is the source code for the 2-parameter implementation of Handler to help illustrate the bounds of the handler call after argument extraction:

impl<Func, Arg1, Arg2, Fut> Handler<(Arg1, Arg2)> for Func
where
    Func: Fn(Arg1, Arg2) -> Fut + Clone + 'static,
    Fut: Future,
{
    type Output = Fut::Output;
    type Future = Fut;

    fn call(&self, (arg1, arg2): (Arg1, Arg2)) -> Self::Future {
        (self)(arg1, arg2)
    }
}

Required Associated Types§

source

type Output

source

type Future: Future<Output = Self::Output>

Required Methods§

source

fn call(&self, args: Args) -> Self::Future

Implementors§

source§

impl<Func, Fut> Handler<()> for Funcwhere Func: Fn() -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A> Handler<(A,)> for Funcwhere Func: Fn(A) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B> Handler<(A, B)> for Funcwhere Func: Fn(A, B) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B, C> Handler<(A, B, C)> for Funcwhere Func: Fn(A, B, C) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B, C, D> Handler<(A, B, C, D)> for Funcwhere Func: Fn(A, B, C, D) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B, C, D, E> Handler<(A, B, C, D, E)> for Funcwhere Func: Fn(A, B, C, D, E) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B, C, D, E, F> Handler<(A, B, C, D, E, F)> for Funcwhere Func: Fn(A, B, C, D, E, F) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B, C, D, E, F, G> Handler<(A, B, C, D, E, F, G)> for Funcwhere Func: Fn(A, B, C, D, E, F, G) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B, C, D, E, F, G, H> Handler<(A, B, C, D, E, F, G, H)> for Funcwhere Func: Fn(A, B, C, D, E, F, G, H) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B, C, D, E, F, G, H, I> Handler<(A, B, C, D, E, F, G, H, I)> for Funcwhere Func: Fn(A, B, C, D, E, F, G, H, I) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B, C, D, E, F, G, H, I, J> Handler<(A, B, C, D, E, F, G, H, I, J)> for Funcwhere Func: Fn(A, B, C, D, E, F, G, H, I, J) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B, C, D, E, F, G, H, I, J, K> Handler<(A, B, C, D, E, F, G, H, I, J, K)> for Funcwhere Func: Fn(A, B, C, D, E, F, G, H, I, J, K) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut

source§

impl<Func, Fut, A, B, C, D, E, F, G, H, I, J, K, L> Handler<(A, B, C, D, E, F, G, H, I, J, K, L)> for Funcwhere Func: Fn(A, B, C, D, E, F, G, H, I, J, K, L) -> Fut + Clone + 'static, Fut: Future,

§

type Output = <Fut as Future>::Output

§

type Future = Fut