Visitors

Hot Chocolate creates an abstract syntax tree for every incoming request. Here you find more information about the Abstract Syntax Tree (AST). 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 semantic of the requested document is 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 Fitlering, 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 generic argument TContext of SyntaxWalker<TContext> denotes the type of the context.

To start the visitation of a GraphQL syntax tree, you have to pass the node and the context the visitation should start from to the visitors Visit method.


Visitation

To start the visitation of a GraphQL syntax tree, you have to pass the node and the context the visitation should start from to the visitors 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 a virtual Enter and a virtual Leave method 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 also 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 give you provide you visual insight on the order of the methods being called.

query GetFoos {
  foo {
    bar
  }
}
RootFooBarOnBeforeEnter `query GetFoos`1Enter `query GetFoos`2OnAfterEnter `query GetFoos`3VisitChildren4OnBeforeEnter foo5Enter foo6OnAfterEnter foo7VisitChildren8...-9OnBeforeLeave foo10Leave foo11OnAfterEnter foo12-13OnBeforeLeave query GetFoos14Leave query GetFoos15OnAfterEnter query GetFoos16RootFooBar
  1. We start walking down the tree and enter.
    Call the OnBeforeEnter(OperationDefinitionNode node, TContext context)
  2. Call the Enter(OperationDefinitionNode node, TContext context)
  3. Call the OnAfterEnter(OperationDefinitionNode node, TContext context)
  4. Call the VisitChildren(OperationDefinitionNode node, TContext context)
  5. Call the OnBeforeEnter(ObjectFieldNode node, TContext context)
  6. Call the Enter(ObjectFieldNode node, TContext context)
  7. Call the OnAfterEnter(ObjectFieldNode node, TContext context)
  8. Call the VisitChildren(ObjectFieldNode node, TContext context)
  9. We walk back up the tree and leave
  10. Call the OnBeforeLeave(ObjectFieldNode node, TContext context)
  11. Call the Leave(ObjectFieldNode node, TContext context)
  12. Call the OnAfterLeave(ObjectFieldNode node, TContext context)
  13. We walk back up the tree and leave.
  14. Call the OnBeforeLeave(OperationDefinitionNode node, TContext context)
  15. Call the Leave(OperationDefinitionNode node, TContext context)
  16. Call the OnAfterLeave(OperationDefinitionNode node, TContext context)

Visitor Actions

The Enter and Leave methods return visitor actions. These methods control the visitors' next step in the visitation. Visitoractions 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

If Continue is returned from the Enter or Leave method visitation on the current branch continues.

In the following example Continue is returned from the onEnter method. The visitor calls VisitChildren and continues to by entering the selection set.

query {
  foo {
    bar
    baz @onEnter(return: SKIP) {      quux
    }
    qux
  }
}

Skip

If Skip is returned from the Enter or Leave method, further visitation on this node stops.

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

If SkipAndLeave is returned from the Enter method, further visitation on this node stops. 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 calls the leaves the field baz by calling Leave

query {
  foo {
    bar
    baz @onEnter(return: SKIPANDLEAVE) {      quux
    }
    qux
  }
}

Break

If Break is returned from the Enter or Leave method, further visitation on this branch stops.

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 selections set of baz it skips baz and qux.

query {
  foo {
    bar
    baz @onEnter(return: BREAK) {      quux
    }
    qux
  }
}