Working with Resolver Context

1. Creating Context Object

PropertyUse
userAuthenticated principal
dbORM/client instance
loadersDataLoader instances
req / headersRaw HTTP request
loggerPer-request scoped logger
requestIdTrace correlation

2. Adding User Authentication

Example: Verify JWT in context

context: async ({ req }) => {
  const token = req.headers.authorization?.replace(/^Bearer /, "");
  const user = token ? await verifyJWT(token) : null;
  return { user };
}

3. Adding Database Connections

StrategyDetail
Singleton clientPrisma/Knex shared across requests
Per-request transactionBegin/commit around operation
Read replicaRoute Query → replica, Mutation → primary

4. Adding Data Loaders

Example: Per-request loaders

function createLoaders(db) {
  return {
    userById: new DataLoader(ids => batchUsers(db, ids)),
    postsByUser: new DataLoader(ids => batchPostsByUser(db, ids))
  };
}

context: ({ req }) => ({ db, loaders: createLoaders(db) })
Warning: Always create loaders per-request — never share across requests (cache pollution).

5. Adding Request Information

FieldUse
ipRate limiting
userAgentAnalytics
locale / Accept-Languagei18n
headersCustom integration headers

6. Sharing Context Across Resolvers

PatternDetail
Shape stableUse TypeScript type for context
Avoid mutationTreat context as readonly during execution
Lazy initGetters for expensive resources

7. Implementing Context Functions

Example: Apollo Server context fn

const server = new ApolloServer({ schema });
await startStandaloneServer(server, {
  context: async ({ req }) => ({ user: await auth(req), db, loaders: createLoaders() })
});

8. Using Context for Authorization

Example: Role check

Query: {
  adminStats: (_, __, { user }) => {
    if (user?.role !== "ADMIN") throw new GraphQLError("Forbidden", { extensions: { code: "FORBIDDEN" } });
    return computeStats();
  }
}

9. Adding Logger to Context

PatternBenefit
Child logger per requestInherits requestId, userId
Pino / WinstonStructured JSON logs
OpenTelemetryAuto-correlates logs ↔ spans

10. Managing Context Lifecycle

PhaseAction
CreateBuild per request
UseAvailable in every resolver
CleanupPlugin willSendResponse closes resources
SubscriptionsBuild per WebSocket connection AND per operation