v5 (latest)
Features
GraphQL Context

GraphQL Context

A context is usually created for each execution of a GraphQL Operation, and it is injected into the GraphQL field resolver functions. It is commonly used for doing dependency injection, e.g. if you want to access the current user or other information.

Within GraphQL Yoga, the context object is constructed for each incoming 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 for authenticating a client
  • params - Parameters of GraphQL Request
    • query - the DocumentNode that was parsed from the GraphQL query string sent by a client
    • operationName - the operation name selected from the incoming query sent by a client
    • variables - the variables that were defined in the query sent by a client
    • extensions - the extensions that were received from the client sent by a client

Context Usage Example: Log Headers

Context Usage Log Headers
import { createServer } from 'http'
import { createSchema, createYoga } from 'graphql-yoga'
 
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, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})
Execute operation and see logs in terminal
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 providing a context property to the createYoga call.

Example: Object

Extending Context
import { createServer } from 'http'
import { createSchema, createYoga } from 'graphql-yoga'
 
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, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})

Instead, 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. The context returned from that function will be merged with the initial context.

Example: Function Returning an Object

Returning function for context
import { createServer } from 'http'
import { createSchema, createYoga } from 'graphql-yoga'
 
const yoga = createYoga({
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      type Query {
        someNumber: Int!
      }
    `,
    resolvers: {
      Query: {
        someNumber(_, _args, context) {
          return context.someNumber
        }
      }
    }
  }),
  context() {
    return { someNumber: 13 }
  }
})
 
const server = createServer(yoga)
server.listen(4000, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})

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

Example: Function Returning a Promise

Returning promise for context creation
import { createServer } from 'http'
import { createSchema, createYoga } from 'graphql-yoga'
 
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, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})

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, or, if you are just curious about how Yoga works in depth, this might also be interesting information for you!

There are in total four steps that GraphQL Yoga follows to generate the final context object.

  • Default Context - created for each incoming request and the same on all platforms
  • Server Context - depends on the platform (Node.js/Deno/etc.) and the framework (raw Node.js/express/fastify)
  • User Context - created for each incoming request with access to the default and server context
  • Envelop Plugin Context - created 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 createServer from the http(s) module or exposing it as a middleware as we show in the express or Next.js integration 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 and platform independent (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 non standard 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 createYoga for correctly typing the server context.

Typing request for Fastify integration
const yoga = createYoga<{
  req: FastifyRequest
  reply: FastifyReply
}>()
 
// somewhere within the request handler
 
const response = await yoga.handleNodeRequestAndResponse(req, reply, {
  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 createYoga 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.

User context factory function
import { createServer } from 'http'
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, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})

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.