SolvedRocket Object available to every route ad-hoc

It's not obvious how to make an object or some data available to all routes (ad-hoc). I'm thinking something like a DB connection pool object that would get passed to every route as an argument.

How would one do that with rocket?

19 Answers

✔️Accepted Answer

For the same reasons you'd use a request guard otherwise: so that a handler's signature directly declares its requirements, and as a mechanism for centralizing policy. The former is straightforward, but the latter may seem irrelevant here. Let me explain.

Say you were to use r2d2 to get a connection via pool::get. The method returns a Result, so you need to do something in the case of Err. It's likely that you always want to do the same thing, and let's say that it's to return a 503 Service Unavailable if there is no connection available. A request guard lets you do this for every route that needs a connection, in one go, and it makes it so that the type is what is controlling the behavior. The type directly encapsulates what it means to have a connection or be unable to get one. Not only does this result in less code, but it also results in richer types.

On a more practical note, Rocket is likely to ship with a library for handling database connections in the near future, and it'll almost certainly use request guards for the reasons I mention above. Doing it this way as well, while there's no official library, will let you migrate to the official solution in short order. :)

Other Answers:

Indeed, using lazy_static! and RequestGuards seems a tad too much, especially if you have a lot of stuff to make available.

This is how I set up usage of a DB connection pool:

lazy_static! {
    pub static ref DB_POOL: r2d2::Pool<ConnectionManager<PgConnection>> = {
        let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set.");
        let config = r2d2::Config::default();
        let manager = ConnectionManager::<PgConnection>::new(database_url);
        let pool = r2d2::Pool::new(config, manager).expect("Failed to create pool.");
        pool
    };
}

pub struct DB(r2d2::PooledConnection<ConnectionManager<PgConnection>>);

impl DB {
    pub fn conn(&self) -> &PgConnection {
        &*self.0
    }
}

impl<'a, 'r> FromRequest<'a, 'r> for DB {
    type Error = r2d2::GetTimeout;
    fn from_request(_: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
        match DB_POOL.get() {
            Ok(conn) => Success(DB(conn)),
            Err(e) => Failure((Status::InternalServerError, e)),
        }
    }
}

The ceremonial practice of settings up the lazy_static! and making it available as a RequestGuards could surely be abstracted away in to a higher level API which would make it much easier to do.

More Issues: