Trait rocket::route::Handler[][src]

pub trait Handler: Cloneable + Send + Sync + 'static {
    #[must_use]
    fn handle<'r, 'life0, 'life1, 'async_trait>(
        &'life0 self,
        request: &'r Request<'life1>,
        data: Data<'r>
    ) -> Pin<Box<dyn Future<Output = Outcome<'r>> + Send + 'async_trait>>
    where
        'r: 'async_trait,
        'life0: 'async_trait,
        'life1: 'async_trait,
        Self: 'async_trait
; }
Expand description

Trait implemented by Route request handlers.

In general, you will never need to implement Handler manually or be concerned about the Handler trait; Rocket’s code generation handles everything for you. You only need to learn about this trait if you want to provide an external, library-based mechanism to handle requests where request handling depends on input from the user. In other words, if you want to write a plugin for Rocket that looks mostly like a static route but need user provided state to make a request handling decision, you should consider implementing a custom Handler.

Async Trait

This is an async trait. Implementations must be decorated #[rocket::async_trait].

Example

Say you’d like to write a handler that changes its functionality based on an enum value that the user provides:

#[derive(Copy, Clone)]
enum Kind {
    Simple,
    Intermediate,
    Complex,
}

Such a handler might be written and used as follows:

use rocket::{Request, Data};
use rocket::route::{Handler, Route, Outcome};
use rocket::http::Method;

#[derive(Clone)]
struct CustomHandler(Kind);

#[rocket::async_trait]
impl Handler for CustomHandler {
    async fn handle<'r>(&self, req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r> {
        match self.0 {
            Kind::Simple => Outcome::from(req, "simple"),
            Kind::Intermediate => Outcome::from(req, "intermediate"),
            Kind::Complex => Outcome::from(req, "complex"),
        }
    }
}

impl Into<Vec<Route>> for CustomHandler {
    fn into(self) -> Vec<Route> {
        vec![Route::new(Method::Get, "/", self)]
    }
}

#[rocket::launch]
fn rocket() -> _ {
    rocket::build().mount("/", CustomHandler(Kind::Simple))
}

Note the following:

  1. CustomHandler implements Clone. This is required so that CustomHandler implements Cloneable automatically. The Cloneable trait serves no other purpose but to ensure that every Handler can be cloned, allowing Routes to be cloned.
  2. CustomHandler implements Into<Vec<Route>>, allowing an instance to be used directly as the second parameter to rocket.mount().
  3. Unlike static-function-based handlers, this custom handler can make use of any internal state.

Alternatives

The previous example could have been implemented using a combination of managed state and a static route, as follows:

use rocket::State;

#[get("/")]
fn custom_handler(state: &State<Kind>) -> &'static str {
    match state.inner() {
        Kind::Simple => "simple",
        Kind::Intermediate => "intermediate",
        Kind::Complex => "complex",
    }
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![custom_handler])
        .manage(Kind::Simple)
}

Pros:

  • The handler is easier to implement since Rocket’s code generation ensures type-safety at all levels.

Cons:

  • Only one Kind can be stored in managed state. As such, only one variant of the custom handler can be used.
  • The user must remember to manually call rocket.manage(state).

Use this alternative when a single configuration is desired and your custom handler is private to your application. For all other cases, a custom Handler implementation is preferred.

Required methods

#[must_use]
fn handle<'r, 'life0, 'life1, 'async_trait>(
    &'life0 self,
    request: &'r Request<'life1>,
    data: Data<'r>
) -> Pin<Box<dyn Future<Output = Outcome<'r>> + Send + 'async_trait>> where
    'r: 'async_trait,
    'life0: 'async_trait,
    'life1: 'async_trait,
    Self: 'async_trait, 
[src]

Called by Rocket when a Request with its associated Data should be handled by this handler.

The variant of Outcome returned by the returned Future determines what Rocket does next. If the return value is a Success(Response), the wrapped Response is used to respond to the client. If the return value is a Failure(Status), the error catcher for Status is invoked to generate a response. Otherwise, if the return value is Forward(Data), the next matching route is attempted. If there are no other matching routes, the 404 error catcher is invoked.

Implementors

impl Handler for FileServer[src]

fn handle<'r, 'life0, 'life1, 'async_trait>(
    &'life0 self,
    req: &'r Request<'life1>,
    data: Data<'r>
) -> Pin<Box<dyn Future<Output = Outcome<'r>> + Send + 'async_trait>> where
    'r: 'async_trait,
    'life0: 'async_trait,
    'life1: 'async_trait,
    Self: 'async_trait, 
[src]

impl<F: Clone + Sync + Send + 'static> Handler for F where
    F: Fn(&'x Request<'_>, Data<'x>) -> BoxFuture<'x>, 
[src]

fn handle<'r, 'life0, 'life1, 'async_trait>(
    &'life0 self,
    req: &'r Request<'life1>,
    data: Data<'r>
) -> BoxFuture<'r> where
    'r: 'async_trait,
    'life0: 'async_trait,
    'life1: 'async_trait,
    Self: 'async_trait, 
[src]