context
You might have noticed that in our load
and resolve
functions that we don't have the request
parameters readily available to us, we might however need them to check i.e. if a user is authorized, ...
This is done through the context
object which will be carried around throughout the whole request lifecycle.
API-Route
By default we will expose params
and headers
on the context object. If you want to expose more data you can do so by
adding it to the function invocation of your API handler.
import { createAPIRouteHandler } from 'fuse/next'
createAPIRouteHandler<{ userAgent: string }>({
context: (ctx) => {
return {
userAgent: ctx.headers.get('user-agent') || 'unknown',
}
}
})
Now the userAgent
will be available to all of our GraphQL resolvers!
Server components
In server-components
we don't have the headers
available by default when using the execute
function, this
to avoid automatically opting people into dynamic functions (opens in a new tab).
We'll have to pass these in with the second argument of our execute
function.
import { headers } from 'next/headers'
import { createAPIRouteHandler } from '@/fuse/server'
execute({
query: x,
variables: {},
context: () => {
return {
userAgent: headers().get('user-agent') || 'unknown'
}
}
})
This means that if you use
context.headers
or a related property in your resolvers that you will need to define this yourself if your executed document would tap into those resolvers.
Using context
in your API
In our fields there are two opportunities we have to use context
the first being during resolve
and the second during load
,
below you can find an example of both.
import { node, addQueryFields, AuthenticationError } from 'fuse'
const UserNode = node<UserSource>({
name: 'User',
load: async (ids, ctx) => ctx.isAdmin ? getUsers(ids) : [],
fields: (t) => ({
name: t.exposeString('name'),
// rename to camel-case
avatarUrl: t.exposeString('avatar_url'),
// Add an additional firstName field
firstName: t.string({
resolve: (user) => user.name.split(' ')[0],
}),
}),
})
addQueryFields((t) => ({
me: t.list({
type: UserNode,
nullable: false,
args: {
offset: t.arg.int({}),
limit: t.arg.int(),
filter: t.arg({ type: FilterInput }),
},
resolve: async (_, args, context) => {
if (context.userId) {
return context.userId
}
throw new AuthenticationError('You must be logged in.')
},
}),
}))