0

can anyone help get my head around the FromRequest trait.

As I understand, we can use it to share data with the resolvers.

I'm trying to inject the http headers so I can authenticate users before some actions in the resolvers.

See my code below.

Looks like the from_request isn't even called.

I'm using rocket 0.5.rc1

Thank you for your help

use juniper::{graphql_object, EmptySubscription, RootNode};
use mongodb::Client;
use mongodb::Database;


use rocket::{catch, catchers};
use rocket::{response::content, Rocket, State};

type Schema = RootNode<'static, Query, Mutations, EmptySubscription<AppContext>>;

use rocket::{
    http::Status,
    request::{FromRequest, Outcome},
    Request,
};

struct Mutations;
struct Query;

#[derive(Debug)]
pub struct AppContext {
    pub mongodb_pool: Database,
    pub user: String,
}

    impl juniper::Context for AppContext {}
    
    #[rocket::async_trait]
    impl<'r> FromRequest<'r> for AppContext {
        type Error = ();
    
        async fn from_request(request: &'r Request<'_>) -> Outcome<AppContext, Self::Error> {
            let client = Client::with_uri_str("mongodb://admin:admin@localhost:28017").await;
            let db = client.unwrap().database("override");
            Outcome::Success(AppContext { mongodb_pool: db, user: "from request".to_string() }, )
        }
    }
    
    #[graphql_object(context = AppContext)]
    impl Query {
        fn api_version(db: &AppContext) -> &str {
            println!("{:?}", db.user);
            "1.0"
        }
    }
    
    #[graphql_object(context = AppContext)]
    impl Mutations {
        fn api_version(db: &AppContext) -> String {
            "1.0".to_string()
        }
    }
    
    #[rocket::get("/")]
    fn graphiql() -> content::Html<String> {
        juniper_rocket::graphiql_source("/graphql", None)
    }
    
    #[rocket::get("/graphql?<request>")]
    async fn get_graphql_handler(
        context: &State<AppContext>,
        request: juniper_rocket::GraphQLRequest,
        schema: &State<Schema>,
    ) -> juniper_rocket::GraphQLResponse {
        request.execute(&*schema, &*context).await
    }
    
    #[rocket::post("/graphql", data = "<request>")]
    async fn post_graphql_handler(
        context: &State<AppContext>,
        request: juniper_rocket::GraphQLRequest,
        schema: &State<Schema>,
    ) -> juniper_rocket::GraphQLResponse {
        request.execute(&*schema, &*context).await
    }
    
    #[tokio::main]
    async fn main() {
        let client = Client::with_uri_str("mongodb://admin:admin@localhost:28017").await;
        let db = client.unwrap().database("app_db");
    
        Rocket::build()
            .manage(AppContext{ mongodb_pool: db, user: "from build".to_string() })
            .manage(Schema::new(
                Query,
                Mutations,
                EmptySubscription::<AppContext>::new(),
            ))
            .mount(
                "/",
                rocket::routes![graphiql, get_graphql_handler, post_graphql_handler],
            )
            .launch()
            .await
            .expect("server failed to launch");
    }
user1445685
  • 793
  • 1
  • 11
  • 25
  • 1
    Using `context: &State` will get the the value that you passed to `.manage()` in `main()`, perhaps you wanted just `context: AppContext`? – kmdreko Jan 02 '22 at 02:50
  • I took my implementation from this repo. https://github.com/graphql-rust/juniper/blob/master/juniper_rocket/examples/rocket_server.rs I started not long ago so I really don't know how to fix my issue. Any source code would be highly appreciated – user1445685 Jan 02 '22 at 23:06
  • 1
    Did what I suggest not fix the issue? You seem to want a new `AppContext` per request and you can do that by *not* using `State<...>`, `State` is for global stuff. Just using `AppContext` directly will create it per-request by using your `FromRequest` implementation. – kmdreko Jan 02 '22 at 23:37
  • Yes. thank you! I'm able to check the headers now. I'm trying to figure out how to still pass the database connections globally. I moved the code from my main function and if I understand it well putting it inside the from_request creates a connection on every request. Right? – user1445685 Jan 03 '22 at 06:15

0 Answers0