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 APIRequest
object that represents the incoming HTTP request in platform-independent way. It can be useful for accessing headers to authenticate a userquery
- theDocumentNode
that was parsed from the GraphQL query stringoperationName
- the operation name selected from the incoming queryvariables
- the variables that were defined in the queryextensions
- 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, () => {
console.info('Server is running on http://localhost:4000/graphql')
})
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, () => {
console.info('Server is running on http://localhost:4000/graphql')
})
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, () => {
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
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 }
}
})
server.listen(4000, () => {
console.info('Server is running on http://localhost:4000/graphql')
})
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. 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.
req
- Node.jsIncomingMessage
objectres
- Node.jsServerResponse
object
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 }
server.listen(4000, () => {
console.info('Server is running on http://localhost:4000/graphql')
})
})
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.