Advanced GraphQL Patterns: The Almighty Root Resolver

Nicola Marcacci Rossi

April 2019

What is an Almighty Root Resolver, and when do you need one? If you want to know the answer, join us in a trip beyond the happy land of local resolvers.

This article assumes some working knowledge of server-side GraphQL, in particular Apollo Server. It is part of a series on enterprise grade GraphQL hosted by smartive.

The Happy Land of Local Resolvers

You know the pitch: to implement a GraphQL server you only have to (1) define your schema and (2) implement the resolvers that take care of bits of the schema.

javascript
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`;
const resolvers = {
Query: {
books: () => { /* get them books */ },
},
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Adapted from Apollo: Getting Started

You need related data? No problem, just define the needed subresolvers. Apollo Server takes care of the rest.

typescript
const typeDefs = gql`
type User {
name: String
}
type Book {
title: String
author: User
}
# ...
`;
const resolvers = {
Book: {
author: (book) => { /* find user by book.authorId */ }
}
/* ... */
};

If the author is already stored inside the book object, e.g. in a MongoDB database, even better. No additional resolver needed.

Beyond the Happy Land

Now, if you are involved in building a complex GraphQL API, there might be a point where you reach the limitations of this approach - Perhaps you need some information about related data in the parent resolver. Perhaps you need data about “grandparent” data in a leaf resolver. Perhaps your API is becoming inefficient and you want to gather more data at once in a higher-level resolver (I call this The Join Problem, to be expanded on in a later article). The happy path of local resolvers isn’t enough anymore.

typescript
const resolvers = {
Query: {
books: () => { /* get the books and if needed each book's author (whew!) */ },
},
};

You find yourself looking at the scary info argument. You manage to hack together a join, but you feel like you are playing around with the internals and hope you will never have to touch it again. You’re deep in the woods.

The Almighty Root Resolver

If you go deeply enough into the thicket, you will end up finding the following pattern:

Pattern: Using the top resolver to (recursively) solve the whole GraphQL query (except, maybe, for calls to external APIs).

If your API requirements have reached this level, welcome to the club. You are implementing an Almighty Root Resolver.

typescript
const resolvers = {
Query: {
books: () => { /* get them books plus any related data needed, recursively! */ },
},
};

To be able to implement such a resolver, you need a way more detailed understanding of the internals of Apollo and of GraphQL query resolution. We will look at this more in depth in this series of articles (with a special focus on MySQL query generation). For now, remember that you are not alone in this, and that this pattern now has a name.

Build Enterprise Grade GraphQL Applications

Want to become a GraphQL pro? Follow us and read our whole series on enterprise-grade GraphQL applications.

Need an expert team to implement your advanced web application? Check out our portfolio. At smartive, we build complex web applications. We are located in Zurich, Switzerland.