Skip to content

Visit

The visit feature provides the infrastructure to traverse and inspect the FunQL Abstract Syntax Tree (AST). It powers other features like validation and can also be extended for custom scenarios such as query analysis, rewriting, or auditing.

This page explains how to enable the visit feature, what it's used for, and how to customize it.

Adding the feature

Use AddVisitFeature() to register the services required to traverse FunQL ASTs:

public sealed class ApiSchema : Schema 
{
    protected override void OnInitializeSchema(ISchemaConfigBuilder schema) 
    {
        schema.AddVisitFeature();
    }
}

This sets up the visit feature with default configurations. Other features (like validate) will leverage it to walk the AST.

Visiting requests

While the visit feature is primarily used by other features, you can also use it directly to traverse the AST. For example, to visit all nodes of a request:

var schema = new ApiSchema(); 
var request = schema.ParseRequest("listSets()");

// Get the request visitor from the Schema
var requestVisitor = schema.SchemaConfig.FindVisitConfigExtension()
    .RequestVisitorProvider(schema.SchemaConfig);

// Visit the request and each of its child nodes
await requestVisitor.Visit(
    request,
    new VisitorState(
        // Callback called upon entering a node
        onEnter: (node, state, token) => Task.CompletedTask,
        // Callback called upon exiting a node
        onExit: (node, state, token) => Task.CompletedTask
    ),
    CancellationToken.None
);

The VisitorState lets you perform custom logic when visiting nodes via the onEnter and onExit callbacks. Each visitor calls these for every node it visits. The callbacks are fully async so you can perform non-blocking work during traversal, like auditing or permission checks.

Advanced configuration

You can customize the visit feature by passing an action to AddVisitFeature():

public sealed class ApiSchema : Schema { 
    protected override void OnInitializeSchema(ISchemaConfigBuilder schema) { 
        schema.AddVisitFeature(config => { 
            // Customize the feature here
            // Example: Provide a custom visitor for field functions (cache 
            // instance to avoid repeated allocations)
            MyCustomFieldFunctionVisitor? visitor = null;
            config.MutableConfig.FieldFunctionVisitorProvider = _ => 
                visitor ??= new MyCustomFieldFunctionVisitor();
        }); 
    }
}

Note

If you introduce custom node types, ensure corresponding visitors properly handle them. Otherwise, traversal may result in exceptions. For example, if you introduce a new FieldFunction type, ensure the FieldFunctionVisitor properly handles the new type.

What's next

See how the visit feature is used in other parts: