Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

request on YogaInitialContext is conflicting with the request on the Koa server context #3145

Open
holzerch opened this issue Dec 20, 2023 · 2 comments
Labels
kind/docs Improvements or additions to documentation

Comments

@holzerch
Copy link
Contributor

holzerch commented Dec 20, 2023

Describe the bug

We integrated GraphQL Yoga with the Koa server as documented here https://the-guild.dev/graphql/yoga-server/docs/integrations/integration-with-koa
and pass the Koa context like this

const response = await yoga.handleNodeRequest(ctx.req, ctx)

The Koa context contains the Koa request as a request property on the context. However the Yoga server assumes that the request property on the context it is actually the internal platform-independent Fetch Request.

This causes problems e.g. in the use-schema plugin (https://github.com/dotansimha/graphql-yoga/blob/main/packages/graphql-yoga/src/plugins/use-schema.ts)

const schemaByRequest = new WeakMap<Request, GraphQLSchema>();
return {
    onRequestParse({ request, serverContext }) {
      return {
        async onRequestParseDone() {
          const schema = await schemaDef({
            ...(serverContext as TServerContext),
            request,
          });
          schemaByRequest.set(request, schema);
        },
      };
    },
    onEnveloped({ setSchema, context }) {
      if (context?.request == null) {
        throw new Error(
          'Request object is not available in the context. Make sure you use this plugin with GraphQL Yoga.',
        );
      }
      const schema = schemaByRequest.get(context.request);
      if (schema == null) {
        throw new Error(
          `No schema found for this request. Make sure you use this plugin with GraphQL Yoga.`,
        );
      }
      setSchema(schema);
    },
  };

During onRequestParseDone the schema is placed in the WeekMap based on the Yoga request, however within onEnveloped the WeakMap is accessed based on the Koa request from the Context. Since this is different the schema cannot be found and the plugin fails.

A potential workaround of removing request from the Koa context before passing it to Yoga doesn't work, because the request is internally referenced from the context and it becomes dysfunctional.

BTW the same issue exists within the useDisableIntrospection plugin.

Your Example Website or App

sorry no example, but the problem should be clear from the description

Steps to Reproduce the Bug or Issue

I hope the above description is enough to understand the issue

Expected behavior

  • Do not assume the request property on the context is the Yoga request

Screenshots or Videos

No response

Platform

  • OS:macOPS
  • NodeJS: 20.9.0
  • @graphql-yoga/* version): 5.0.2

Additional context

No response

@holzerch holzerch changed the title request on 'YogaInitialContext' is conflicting with the request on the Koa server context request on YogaInitialContext is conflicting with the request on the Koa server context Dec 20, 2023
@EmrysMyrddin
Copy link
Collaborator

Hi, thank you for raising this issue.
I'm not sure why the boilerplate is like this in the documentation, I don't think that it is a good idea to pass directly the koa context as the initial GraphQL context.

I would recommend to either remove the context (let Yoga create a new empty one) if you don't need to access Koa's context in the GraphQL context.

const response = await yoga.handleNodeRequest(ctx.req)

If you actually need to access the Koa context via the context (from a resolver or from a plugin hook), I would create a new context and put the Koa context under a dedicated key:

const response = await yoga.handleNodeRequest(ctx.req, { koa: ctx })

This way, you can always access Koa context in resolvers.

For example:

const resolvers = {
  Query: {
    hello: (_, __, context) => {
      const user = await getUserFromHeaders(context.koa.headers)
      return `Hello ${user.name}`
    }
}

@holzerch
Copy link
Contributor Author

Hi Valentin,

thanks very much for the quick reply and solution. Actually your suggestion with { koa: ctx } solves my problem.

I think in general it makes sense to show in the documentation how to forward the ServerContext to the GraphQL Yoga framework as it is a core part. See here: https://the-guild.dev/graphql/yoga-server/docs/features/context#server-context

Maybe updating the example code in the framework would help others not to run in the same issue

@EmrysMyrddin EmrysMyrddin added the kind/docs Improvements or additions to documentation label Dec 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/docs Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants