• v3
  • Features
  • Context

GraphQL Context

A context is usually created for each execution of a GraphQL Operation, and it is passed to the resolver functions as a third argument. You can learn more about Context in GraphQL Tools docs.

It is commonly used for doing dependency injection.

Within GraphQL Yoga, the context object is generated per HTTP request.

Default Context

By default, GraphQL Yoga provides the following values in the context object independently of your environment and setup:

  • request - Fetch API Request object that represents the incoming HTTP request in platform-independent way. It can be useful for accessing headers to authenticate a user
  • query - the DocumentNode that was parsed from the GraphQL query string
  • operationName - the operation name selected from the incoming query
  • variables - the variables that were defined in the query
  • extensions - the extensions that were received from the client

Context Usage Example: Log Headers

import { createYoga, createSchema } from 'graphql-yoga'
import { createServer } from 'http'
 
const yoga = createYoga({
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      type Query {
        logHeader: Boolean
      }
    `,
    resolvers: {
      Query: {
        logHeader(_, _args, context) {
          console.log(context.request.headers.get('x-foo'))
        },
      },
    },
  }),
})
 
const server = createServer(yoga)
server.listen(4000)
curl -X POST http://localhost:4000/graphql \
  -H "content-type: application/json" \
  -H "x-foo: iliketurtles"
  --data-raw '{"query": "query { logHeader }"}'

Extending the Initial Context

You can extend the existing context by using the context property.

Example: Object

import { createYoga, createSchema } from 'graphql-yoga'
import { createServer } from 'http'
 
const yoga = createYoga({
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      type Query {
        someNumber: Int!
      }
    `,
    resolvers: {
      Query: {
        someNumber(_, _args, context) {
          context.someNumber
        },
      },
    },
  }),
  context: { someNumber: 13 },
})
 
const server = createServer(yoga)
server.listen(4000)

You can also pass a function as the context property. The function will be invoked for each incoming GraphQL request with the initial context as an argument and after the invocation it will be merged with the initial context.

Example: Function Returning an Object

import { createYoga, createSchema } from 'graphql-yoga'
import { createServer } from 'http'
 
const yoga = createYoga({
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      type Query {
        someNumber: Int!
      }
    `,
    resolvers: {
      Query: {
        someNumber(_, _args, context) {
          context.someNumber
        },
      },
    }),
  },
  context() {
    return { someNumber: 13 }
  },
})
 
const server = createServer(yoga)
server.listen(4000)

The function can either return an object or a Promise that resolves to an object.

Example: Function Returning a Promise

import { createYoga, createSchema } from 'graphql-yoga'
import { createServer } from 'http'
 
const yoga = createYoga({
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      type Query {
        someNumber: Int!
      }
    `,
    resolvers: {
      Query: {
        someNumber: (_, _args, context) => context.someNumber,
      },
    },
  }),
  async context() {
    return { someNumber: 13 }
  },
})
 
const server = createServer(yoga)
server.listen(4000)

Advanced Context Life-Cycle

For most users, the previous sections are already sufficient. If you, however, need to integrate Yoga with a custom framework and/or want to attach runtime/framework-specific Request/Response objects to the context. Also, if you are just curious about how Yoga works in depth, this might also be interesting to you!

There are 4 steps that GraphQL Yoga follows to generate the final context object:

  • Default Context - this context is constructed for each incoming request and the same on all platforms
  • Server Context - the content of this context extension depends on the platform (Node.js/Deno/etc.) and the framework (raw Node.js/express/fastify)
  • User Context - this context is created for each incoming request with access to the default and server context
  • Envelop Plugin Context - the context from envelop plugins is processed last, the plugins have access to the default context, server context and user context

Default Context

See the above section default context.

Server Context

When creating the server instance, GraphQL Yoga accepts an additional object from your base server framework or library that will be merged with the default context.

Node.js (standalone, express and Next.js etc.)

If you are using GraphQL Yoga as a standalone server with .start() method or exposing it as a middleware as we show in our express and Next.js recipes.

The req and res objects are added to the initial context object.

const serverContext = { ...defaultContext, req, res }

Thus when using @graphql-yoga/node, it is possible to access context.req and context.res within the GraphQL resolvers or the user context factory function.

However, we recommend avoiding using context.req and context.res wherever possible and instead favor context.request, as it is more future-proof (as Node.js HTTP servers adopt the Fetch Response API).

Advanced Node.js frameworks (Fastify/Koa)

You might notice that the middleware implementation is more complex for server frameworks like Fastify and koa, because of their custom request handling behavior. It is not possible to use a basic Node.js RequestListener function.

Since they limit the access to the underlying raw ServerResponse object, the recipes use the .handleIncomingMessage method and pass the server context as the second parameter.

E.g. for Fastify, a Reply object is attached to the server context instead of the Request object, which is an intermediate framework-specific response format. Also, note the generic definition in createServer for correctly typing the server context.

const yoga = createYoga<{
  req: FastifyRequest
  reply: FastifyReply
}>()
 
// somewhere within the request handler
 
const response = await yoga.handleNodeRequest(req, {
  req,
  reply,
})

Fetch API Request compliant environments (Cloudflare Workers/Deno)

If you are using Cloudflare Workers according to the integration guide, the WHATWG FetchEvent object will be added as the server context object. That object is almost identical to what GraphQL Yoga provides you within YogaInitialContext.

User Context

Besides, the initial context generated based on your setup, GraphQL Yoga also accepts a user context object that will be merged with the initial context (built out of the default context and server context). You can pass a factory function to context parameter of createServer configuration. That function will receive the combination of the standard initial context and the server's (if available), then the return value will be merged into that.

import { createYoga } from 'graphql-yoga'
 
const yoga = createYoga({
  context: async ({ request }) => {
    // get custom header value
    const foo = request.headers.get('x-foo') ?? null
    return { foo }
  },
})
 
const server = createServer(yoga)
server.listen(4000)

In this case, your final context object will have an extra foo property.

See the above section extending the initial context for more details and usage examples.

Envelop Plugins

After all of the above, Envelop plugins (if you have some) receive the context object and can modify or extend it. See the documentation for Envelop plugins for more information.

Last updated on September 19, 2022