website/src/docs/hotchocolate/v16/api-reference/visitors.md
Hot Chocolate creates an abstract syntax tree (AST) for every incoming request. The execution engine evaluates this tree in many ways. Validation is a good example: a set of rules is applied to the tree to find semantic flaws.
You typically do not need to access the AST directly. The AST becomes relevant when you need to change execution behavior based on query structure. Features like filtering, sorting, and selection analyze the incoming query and generate expressions from it.
Hot Chocolate provides the SyntaxWalker to traverse these trees. It has built-in logic to walk down a syntax tree.
The SyntaxWalker is stateless. All state lives on a context object passed along during traversal. The generic argument TContext of SyntaxWalker<TContext> denotes the type of that context.
To start visitation, pass the node and context to the visitor's Visit method.
On the way down the tree, the visitor enters each node, gets its children, and enters them. When it reaches a leaf node, it walks back up and leaves all the nodes. The visitor provides virtual Enter and Leave methods for all GraphQL AST node types.
In addition to Enter and Leave, there are convenience methods called immediately before and after: OnBeforeEnter, OnAfterEnter, OnBeforeLeave, OnAfterLeave. These methods can modify the current TContext. They are useful for initializing state. For example, before entering a FieldNode, you might peek at the latest type from the context, look up the corresponding ObjectField, and push it onto the context for use in the Enter method.
In the sequence diagram below, the participants do not represent object instances. Many steps are hidden. The visualization shows the order of method calls.
query GetFoos {
foo {
bar
}
}
sequenceDiagram
autonumber
Root->>Root: OnBeforeEnter `query GetFoos`
Root->>Root: Enter `query GetFoos`
Root->>Root: OnAfterEnter `query GetFoos`
Root->>Foo: VisitChildren
Foo->>Foo: OnBeforeEnter foo
Foo->>Foo: Enter foo
Foo->>Foo: OnAfterEnter foo
Foo->>Bar: VisitChildren
Note right of Bar: ...
Bar-->Foo: -
Foo->>Foo: OnBeforeLeave foo
Foo->>Foo: Leave foo
Foo->>Foo: OnAfterLeave foo
Foo-->Root: -
Root->>Root: OnBeforeLeave `query GetFoos`
Root->>Root: Leave `query GetFoos`
Root->>Root: OnAfterLeave `query GetFoos`
OnBeforeEnter(OperationDefinitionNode node, TContext context).Enter(OperationDefinitionNode node, TContext context).OnAfterEnter(OperationDefinitionNode node, TContext context).VisitChildren(OperationDefinitionNode node, TContext context).OnBeforeEnter(ObjectFieldNode node, TContext context).Enter(ObjectFieldNode node, TContext context).OnAfterEnter(ObjectFieldNode node, TContext context).VisitChildren(ObjectFieldNode node, TContext context).OnBeforeLeave(ObjectFieldNode node, TContext context).Leave(ObjectFieldNode node, TContext context).OnAfterLeave(ObjectFieldNode node, TContext context).OnBeforeLeave(OperationDefinitionNode node, TContext context).Leave(OperationDefinitionNode node, TContext context).OnAfterLeave(OperationDefinitionNode node, TContext context).The Enter and Leave methods return visitor actions that control the next step.
If Continue is returned, visitation on the current branch continues. The visitor calls VisitChildren and enters the next node.
query {
foo {
bar
baz @onEnter(return: CONTINUE) {
quux
}
qux
}
}
If Skip is returned, further visitation on this node stops. The visitor skips the node and continues with the next sibling.
query {
foo {
bar
baz @onEnter(return: SKIP) {
quux
}
qux
}
}
If SkipAndLeave is returned from Enter, further visitation on this node stops. The visitor calls the Leave method for the current node before continuing with the next sibling.
query {
foo {
bar
baz @onEnter(return: SKIPANDLEAVE) {
quux
}
qux
}
}
If Break is returned, further visitation on the entire branch stops. The visitor walks back up immediately. For example, returning Break from baz causes the visitor to skip baz and qux and call Leave on foo.
query {
foo {
bar
baz @onEnter(return: BREAK) {
quux
}
qux
}
}