A resolver is a function that’s responsible for populating the data for a single field in your schema. It can populate that data in any way you define, such as by fetching data from a back-end database or a third-party API.
If you don’t define a resolver for a particular field, Apollo Server automatically defines a default resolver for it.
type User { id: ID! name: String } type Query { user(id: ID!): User }
// resolvers.ts const users = [ { id: '1', name: 'Elizabeth Bennet' }, // ... ]; const resolvers = { Query: { user(parent, args, context, info) { return users.find(user => user.id === args.id); } } }
When a field is executed, the corresponding resolver is called to produce the next value. If a field produces a scalar value like a string or number, then the execution completes. However if a field produces an object value then the query will contain another selection of fields which apply to that object. This continues until scalar values are reached. GraphQL queries always end at scalar values.
The context
argument is useful for passing things that any resolver might need, like authentication scope, database connections, and custom fetch functions. If you’re using dataloaders to batch requests across resolvers, you can attach them to the context
as well.
To provide an initial context
to your resolvers, add a context
initialization function to the ApolloServer
constructor. This function is called with every request, so you can customize the context based on each request’s details (such as HTTP headers).
// Constructor const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => ({ authScope: getScope(req.headers.authorization) }) })); // Example resolver (parent, args, context, info) => { if(context.authScope !== ADMIN) throw new AuthenticationError('not admin'); // Proceed }