Search code examples
rustrust-dieselrust-rocket

Accessing the Rocket 0.4 database connection pool in a request guard


I am creating a webapp with authentication using Rocket. To do this, I created a User struct that implements FromRequest. It takes the authorization header, which contains a JSON Web Token. I deserialize this token to obtain the payload, and then I query the user from the database. This means that the FromRequest implementation needs a diesel::PgConnection. In Rocket 0.3 this meant calling PgConnection::establish, but with Rocket 0.4 we have access to a connection pool. Normally I would access this connection pool as follows:

fn get_data(conn: db::MyDatabasePool) -> MyModel {
    MyModel::get(&conn)
}

However, within the impl block for FromRequest I can not just add the conn argument to the argument list of from_request function. How do I access my connection pool outside of a request guard?


Solution

  • The Rocket guide for database state says:

    Whenever a connection to the database is needed, use your [database pool] type as a request guard

    Since a database pool can be created via FromRequest and you are implementing FromRequest, use the existing implementation via DbPool::from_request(request):

    use rocket::{
        request::{self, FromRequest, Request},
        Outcome,
    };
    
    // =====
    // This is a dummy implementation of a pool
    // Refer to the Rocket guides for the correct way to do this
    struct DbPool;
    
    impl<'a, 'r> FromRequest<'a, 'r> for DbPool {
        type Error = &'static str;
    
        fn from_request(_: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
            Outcome::Success(Self)
        }
    }
    // =====
    
    struct MyDbType;
    
    impl MyDbType {
        fn from_db(_: &DbPool) -> Self {
            Self
        }
    }
    
    impl<'a, 'r> FromRequest<'a, 'r> for MyDbType {
        type Error = &'static str;
    
        fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
            let pool = DbPool::from_request(request);
            pool.map(|pool| MyDbType::from_db(&pool))
        }
    }