1

I'm using the Rocket web framework in Rust and I have a database pool (DbConn).

#[database("redirect-api")]
pub struct DbConn(diesel::PgConnection);

I have been able to pass DbConn to each route but I am having trouble when trying to pass it to a function that is called by from_request. In get_redirects I use the ApiKey struct, and how I understand it, FromRequest is a guard that checks the input. In from_request, I call the is_valid function but can't pass it the DbConn, like I could if I was calling is_valid from a route, like directly from get_redirects.

I want to be able to use DbConn in the is_valid function, but I get this error if I try to use &DbConn

the trait `diesel::Connection` is not implemented for `fn(PooledConnection<<diesel::PgConnection as Poolable>::Manager>) -> DbConn {DbConn}`
   |
43 |         .load::<Token>(&DbConn)
   |                        ^^^^^^^ the trait `diesel::Connection` is not implemented for `fn(PooledConnection<<diesel::PgConnection as Poolable>::Manager>) -> DbConn {DbConn}`
   |
   = note: required because of the requirements on the impl of `LoadQuery<fn(PooledConnection<<diesel::PgConnection as Poolable>::Manager>) -> DbConn {DbConn}, models::Token>` for `diesel::query_builder::SelectStatement<schema::tokens::table, query_builder::select_clause::DefaultSelectClause, query_builder::distinct_clause::NoDistinctClause, query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<schema::tokens::columns::token, diesel::expression::bound::Bound<diesel::sql_types::Text, std::string::String>>>, query_builder::order_clause::NoOrderClause, query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<BigInt, i64>>>`
#![feature(decl_macro)]
use rocket::{catchers, routes};

#[macro_use]
extern crate diesel;
#[macro_use]
extern crate rocket_contrib;
use diesel::prelude::*;
// --snip--

#[database("redirect-api")]
pub struct DbConn(diesel::PgConnection);
// --snip--

fn is_valid(key: &str) {
    // ... use key, hash is, etc
    // check if hash is in database
    // this function needs the database pool or DbConn
    // but it can't be passed through FromRequest
}

impl<'a, 'r> FromRequest<'a, 'r> for ApiKey {
    type Error = ApiKeyError;

    fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
        let keys: Vec<_> = request.headers().get("x-api-key").collect();
        match keys.len() {
            0 => Outcome::Failure((Status::BadRequest, ApiKeyError::Missing)),
            1 if is_valid(keys[0]) => Outcome::Success(ApiKey(keys[0].to_string())),
            1 => Outcome::Failure((Status::BadRequest, ApiKeyError::Invalid)),
            _ => Outcome::Failure((Status::BadRequest, ApiKeyError::BadCount)),
        }
    }
}
// --snip--

#[get("/redirects")]
pub fn get_redirects(_key: ApiKey, conn: DbConn) -> String {
    // ... do database things with conn
    format!("something {}", some_value_from_db)
}

// --snip--

fn main() {
    rocket::ignite()
        .register(catchers![not_found])
        .attach(DbConn::fairing())
        .mount("/", routes![root, get_redirect])
        .launch();
}
Dzjek R
  • 53
  • 3
  • 1
    Not sure I understand the issue, if `DbConn` works for your normal endpoints then you should be able to get it from the request in `from_request`. Try `request.guard::()`. – kmdreko Jun 01 '21 at 06:22

0 Answers0