Hot Chocolate creates an abstract syntax tree for every incoming request. The execution engine evaluates this syntax tree in many different ways. Validation is a good example. Every incoming request has to be validated. The execution engine has to be sure that the semantics of the requested document are correct. A set of rules is applied to the syntax tree, to find potential semantic flaws.
Usually, you do not have to access the AST directly. The AST only becomes significant, when you want to change execution behavior based on the structure of the query. For example features like Filtering, Sorting, or Selection analyze the incoming query and generate expressions based on it.
Hot Chocolate provides you with different APIs that support you to traverse these trees.
The SyntaxWalker
is a visitor that has built-in all the logic to walk down a syntax tree.
The SyntaxWalker
is completely stateless. All the state is on a context object that is passed along.
The type of the context is denoted by the generic argument TContext
in SyntaxWalker<TContext>
.
Visitation
To start the visitation of a GraphQL syntax tree, you have to pass the node and the context that the visitation should start from to the visitor's Visit
method.
On its way down the syntax tree, the visitor enters a node. The visitor then gets the children of the current node and enters its children.
Once the visitor reached a leaf node, it starts walking back up the tree and leaves all the nodes.
The visitor provides virtual Enter
and Leave
methods for all GraphQL AST nodes.
These methods are called from the visitor as it enters or leaves a node.
The syntax walker provides a few methods in addition to the Enter
and Leave
methods.
For these two methods, there are convenience methods that are called right before and after the method call.
Namely, OnBeforeEnter
, OnAfterEnter
, OnBeforeLeave
, OnAfterLeave
.
These methods can modify the current TContext
.
These before and after methods are good places to initialize state that is used in the main enter or leave method.
e.g. before entering a FieldNode
, you may want to peek the latest type from the context
and get the instance of the ObjectField
corresponding to FieldNode
of this type.
You may also want to push this type onto the context to then use it in the Enter
method.
⚠️ NOTE: In the following sequence diagram the participants do NOT represent any object instances. Furthermore, many steps are hidden in this example. The visualization below should just provide you visual insight on the order of the methods being called.
query GetFoos { foo { bar }}
- We start walking down the tree and enter.
- Call
OnBeforeEnter(OperationDefinitionNode node, TContext context)
- Call
Enter(OperationDefinitionNode node, TContext context)
- Call
OnAfterEnter(OperationDefinitionNode node, TContext context)
- Call
VisitChildren(OperationDefinitionNode node, TContext context)
- Call
OnBeforeEnter(ObjectFieldNode node, TContext context)
- Call
Enter(ObjectFieldNode node, TContext context)
- Call
OnAfterEnter(ObjectFieldNode node, TContext context)
- Call
VisitChildren(ObjectFieldNode node, TContext context)
- We walk back up the tree and leave
- Call
OnBeforeLeave(ObjectFieldNode node, TContext context)
- Call
Leave(ObjectFieldNode node, TContext context)
- Call
OnAfterLeave(ObjectFieldNode node, TContext context)
- We walk back up the tree and leave.
- Call
OnBeforeLeave(OperationDefinitionNode node, TContext context)
- Call
Leave(OperationDefinitionNode node, TContext context)
- Call
OnAfterLeave(OperationDefinitionNode node, TContext context)
Visitor Actions
The Enter and Leave methods return visitor actions. These methods control the visitor's next step in the visitation. Visitor actions can be used to skip further visitation and step back up, or to continue and walk the current branch of the tree further down.
Continue
Returning Continue
from the Enter
or Leave
methods indicates that the visitation shall continue on the current branch.
In the following example Continue
is returned from the onEnter method. The visitor calls VisitChildren
and continues by entering the selection set.
query { foo { bar baz @onEnter(return: CONTINUE) { quux } qux }}
Skip
Returning Skip
is returned from the Enter
or Leave
methods indicates that any further visitation on this node shall be stopped.
In the following example, Skip
is returned from the onEnter method.
The visitor skips the field baz. It continues visitation by entering the field qux:
query { foo { bar baz @onEnter(return: SKIP) { quux } qux }}
SkipAndLeave
Returning SkipAndLeave
from the Enter
method indicates that any further visitation on this node shall be stopped.
Instead of directly calling the next Enter
method, the visitor calls the Leave
method of the current node first.
In the following example SkipAndLeave
is returned from the onEnter method.
The visitor skips the field baz. Before it continues visitation with the field qux it leaves the field baz by calling Leave
:
query { foo { bar baz @onEnter(return: SKIPANDLEAVE) { quux } qux }}
Break
Returning Break
is from the Enter
or Leave
methods indicates that any further visitation on this branch shall be stopped.
In the following example Break
is returned from the onEnter method. The visitor immediately starts walking back up.
The visitor calls the Leave
on foo
instead of visiting the selection set of baz it skips baz and qux.
query { foo { bar baz @onEnter(return: BREAK) { quux } qux }}