Rocket icon indicating copy to clipboard operation
Rocket copied to clipboard

Allow catcher to access rucket::state

Open kaplanelad opened this issue 3 years ago • 0 comments

Is your feature request motivated by a concrete problem? Please describe.

When i'm implement #[catch(default)] function to catch any error in the API, i can't access to rocket::State. Adding state: &State<StateContext> to the catch function getting the attached error:

catchers optionally take `&Request` or `Status, &Request`

Is your feature request motivated by a concrete problem? Please describe. Example:

#[macro_use] extern crate rocket;
use rocket::request::Request;
use rocket::State;
use rocket::http::Status;

struct StateContext {
    foo: String
}

#[get("/info")]
fn info(state: &State<StateContext>) -> &'static str {
    println!("state foo value: {}", state.foo);
    "Hello, world!"
}

#[catch(default)]
fn default(status: Status, req: &Request, state: &State<StateContext>) -> String {
    println!("state foo value: {}", state.foo);
    format!("Sorry, '{}' is not a valid path.", req.uri())
}

#[launch]
fn rocket() -> _ {
    let config = StateContext {
        foo: "bar".to_string()
    };

    rocket::build()
        .manage(config)
        .mount("/", routes![info])
        .register("/", catchers![default])
}

Why this feature can't or shouldn't live outside of Rocket

The state should be a part of the Rucket interface

Ideal Solution

Function that using #[catch(default)] or #[catch(404)] can get rucket state

kaplanelad avatar Jul 21 '22 08:07 kaplanelad

Rocket doesn't let you put guard arguments on error catchers because that would make them faillible/forwardable too... but they're supposed to catch all errors.

However, if you look at the Request type, you'll see that it has a Request::guard method that you can use to retrieve your state. This is the method that's used when rocket expands the #[get] macro-attribute on your usual handlers ; it will work the same way.

#[catch(default)]
fn default(status: Status, req: &Request) -> String {
    // Notice the `unwrap` here. If you're sure that the state will be defined, you can keep it
    // but remember that panicking is not a proper way to handle errors in Rust.
    let state = req.guard::<State<StateContext>>().unwrap();

    println!("state foo value: {}", state.foo);
    format!("Sorry, '{}' is not a valid path.", req.uri())
}

edgarogh avatar Aug 29 '22 10:08 edgarogh

Sound good! thanks @edgarogh

kaplanelad avatar Aug 29 '22 10:08 kaplanelad