Life of a GraphQL Query — Validation

A few weeks ago I wrote about the first phase of what happens when a GraphQL query is executed: lexing and parsing.

We left off with an AST representation of a query which we obtained from the parser.

At this point we know the query is syntactically correct, but that doesn’t necessarily mean we can execute it.

Many things could be wrong with the query. The Author type could very well not have a username field, the argument id could be of type Int, etc.. The parser doesn't care about this. Instead, that is the job of the validation phase.

The GraphQL specification has an entire section that covers validation. Each validation rule is explained in detail accompanied by a pseudo implementation and examples of queries that pass/fail the rule. It’s a great resource that I’ve used countless amount of times when I wasn’t sure about a validation or when I wanted to confirm a behaviour in the GraphQL implementation that I was using.

After digging into various GraphQL implementations like GraphQL Ruby, Sangria, and GraphQL.js I noticed they all have one thing in common when it comes to validation: the visitor pattern.

While Wikipedia provides a theoretical explanation of the visitor pattern, I’d like to explore how it’s used in GraphQL implementations to power the validation phase. We’ll also look at some sample code from GraphQL.js.

First, let’s start with a simple query and its AST representation:

In order to determine whether the query can be executed or not, GraphQL.js’ validate function will traverse the AST using a depth-first traversal. In other words, it will start at the root of the AST (in this case, the Document node) and it will explore as far as possible along the first branch before backtracking and continuing on to the next branch.

Depth-first traversal of our example query
Depth-first traversal of our example query

Visitors (in this case, validations rules) can watch as the AST is being traversed and perform actions when a certain type of node is reached. In GraphQL.js, visitors can be implemented in different ways, but in their simplest form they are an object with a enter and leave function.

During the traversal, when a node is reached the enter function of the visitor will get called. When backtracking, the visitor's leave function gets called.

Here’s a simple visitor that logs whenever a node is entered or left. Notice in this example we are using GraphQL.js’ visit function to traverse the AST. This is the same function that validate uses.

Some GraphQL rules might only be interested by a specific type of node. For example, a rule might want to validate that an OperationDefinition always has a name (i.e. query Name { .. }.) For this reason each GraphQL.js rule can decide to hook onto individual types of nodes. This can be done by nesting the enter and leave functions under a key named the same as the kind of AST node of interest.

Here’s an example of a visitor that only cares about when an OperationDefinition node is entered:

The OperationDefinition key in the above example can be replaced with any valid AST node kind to observe that kind of node. A visitor can also observe multiple node kinds at once by setting the corresponding keys.

Now that we have a better understanding of the visitor pattern and how visitors are implemented in GraphQL.js, we can add the missing parts to turn this visitor into a GraphQL.js validation rule.

If you’re interested in learning more about the validation phase, check out GraphQL.js’ src/validation folder. A lot of what was discussed is explained as comments in the code.

While writing this article I started a project called GraphQL Schema Linter which is built on top of GraphQL.js’ validate and visit functions. I'm always looking for help so whether you are new to this or not come join the discussions in the repository.