pub trait Handler:
Cloneable
+ Send
+ Sync
+ 'static {
// Required method
fn handle<'r>(&self, request: &'r Request<'_>, data: Data) -> Outcome<'r>;
}
Expand description
Trait implemented by types that can handle requests.
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
.
§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, Route, http::Method};
use rocket::handler::{self, Handler, Outcome};
#[derive(Clone)]
struct CustomHandler(Kind);
impl Handler for CustomHandler {
fn handle<'r>(&self, req: &'r Request, data: Data) -> 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)]
}
}
fn main() {
rocket::ignite()
.mount("/", CustomHandler(Kind::Simple))
.launch();
}
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 {
Kind::Simple => "simple",
Kind::Intermediate => "intermediate",
Kind::Complex => "complex",
}
}
fn main() {
rocket::ignite()
.mount("/", routes![custom_handler])
.manage(Kind::Simple)
.launch();
}
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>(&self, request: &'r Request<'_>, data: Data) -> Outcome<'r>
fn handle<'r>(&self, request: &'r Request<'_>, data: Data) -> Outcome<'r>
Called by Rocket when a Request
with its associated Data
should be
handled by this handler.
The variant of Outcome
returned 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.