graphql-rust / juniper

GraphQL server library for Rust
Other
5.66k stars 420 forks source link

Trouble Defining Lifetime on Context with Juniper and Rocket Async #850

Open JonRCahill opened 3 years ago

JonRCahill commented 3 years ago

I need to define a lifetime on my Context so I can gain access to Cookies in Rocket, but after defining the lifetime I get a compile error on the get_graphql_handler request handler.

A simplified version (without the Cookies) which has the same compile error:

pub struct Context<'a> {
    _marker: std::marker::PhantomData<&'a ()>,
}
impl<'a> Context<'a> {
    pub async fn get_something(&self) -> FieldResult<String> {
        Ok("Something".into())
    }
}
impl<'a> juniper::Context for Context<'a> {}

pub struct QueryRoot<'a> {
    _marker: std::marker::PhantomData<&'a ()>,
}

#[graphql_object(Context = Context<'a>)]
impl<'a> QueryRoot<'a> {
    async fn something(context: &Context<'a>) -> FieldResult<String> {
        context.get_something().await
    }
}

pub type Schema<'a> = juniper::RootNode<
  'static,
  QueryRoot<'a>,
  EmptyMutation<Context<'a>>,
  EmptySubscription<Context<'a>>,
>;

#[get("/graphql?<request>")]
pub async fn get_graphql_handler<'a>(
    request: juniper_rocket_async::GraphQLRequest,
    schema: State<'_, Schema<'a>>,
    context: Context<'a>,
) -> juniper_rocket_async::GraphQLResponse {
    request.execute(&schema, &context).await
}

Results in the following compile errors:


error[E0308]: mismatched types
  --> server/src/graphql/handlers.rs:12:1
   |
12 | #[get("/graphql?<request>")]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected type `context::Context<'_>`
            found struct `context::Context<'_>`
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0621]: explicit lifetime required in the type of `__req`
  --> server/src/graphql/handlers.rs:12:1
   |
12 | #[get("/graphql?<request>")]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   | |
   | lifetime `'_b` required
   | help: add explicit lifetime `'_b` to the type of `__req`: `&'_b rocket::Request<'_b>`
   |
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

I have created an example here: https://github.com/JonRCahill/juniper_context_lifetimes

Any ideas what I need to do to get this to compile?

GavinMendelGleason commented 1 year ago

Presumably the macrology does not understand the lifetime parameter, but I have a similar need to carry a lifetime and would like to avoid having to do everything using the dynamic approach in order to make it work. Any known work-arounds here?

tyranron commented 1 year ago

@JonRCahill @GavinMendelGleason this topic has been araised multiple times already across issues (https://github.com/graphql-rust/juniper/issues/143, https://github.com/graphql-rust/juniper/issues/105, https://github.com/graphql-rust/juniper/issues/364). Unfortunately, seems to be no handy way to have any lifetime parameters in Context type at the moment. As far as I recall, the issue is not that much with juniper macros expansion, but rather with some core type machinery or web-framework integration crates not being able to extract a Context with lifetime from web-framework's request context. Try to do the manual extraction Context<'a> inside the handler, not requiring it as a function argument.