pub trait Handler: Cloneable + Send + Sync + 'static {
// Required method
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 Self: 'async_trait,
'r: 'async_trait,
'life0: 'async_trait,
'life1: '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:
CustomHandler
implementsClone
. This is required so thatCustomHandler
implementsCloneable
automatically. TheCloneable
trait serves no other purpose but to ensure that everyHandler
can be cloned, allowingRoute
s to be cloned.CustomHandler
implementsInto<Vec<Route>>
, allowing an instance to be used directly as the second parameter torocket.mount()
.- 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§
sourcefn 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
Self: 'async_trait,
'r: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
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 Self: 'async_trait, 'r: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,
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.