Apply directives

Directives are annotations for your GraphQL schema or operations.

See also

Tanka GraphQL provides support for execution and schema directives:

  • Execution directives: Include and Skip
  • Schema directives

Currrently schema directives are only supported on fields of object types

Schema directives

Schema directives can be used to modify field for example by modifying the resolver of the field.


    [Fact]
    public async Task Part3_ApplyDirectives_on_Object_fields()
    {
        // Create builder, load sdl with our types
        // and bind the resolvers
        var builder = new SchemaBuilder()
            .Add(@"
                    directive @duplicate on FIELD_DEFINITION

                    type Query {
                        name: String @duplicate                
                    }
                    ");

        // build schema with resolvers and directives
        var schema = await builder.Build(new SchemaBuildOptions
        {
            Resolvers = new ResolversMap
            {
                {
                    "Query", new FieldResolversMap
                    {
                        {
                            "name", () => "Test"
                        }
                    }
                }
            },
            DirectiveVisitorFactories = new Dictionary<string, CreateDirectiveVisitor>
            {
                // Apply directives to schema by providing a visitor which
                // will transform the fields with the directive into new
                // fields with the directive logic. Note that the original
                // field will be replaced.
                ["duplicate"] = _ => new DirectiveVisitor
                {
                    // Visitor will visit field definitions
                    FieldDefinition = (directive, fieldDefinition) =>
                    {
                        // We will create new field definition with 
                        // new resolver. New resolver will execute the 
                        // original resolver, duplicate value and return it
                        return fieldDefinition
                            .WithResolver(resolver =>
                                // we will build a new resolver with a middlware to duplicate the value
                                resolver.Use(next => async context =>
                                {
                                    // We need to first call the original resolver to 
                                    // get the initial value
                                     await next(context);

                                     // context should now have the ResolvedValue set by the original resolver
                                     var resolvedValue = context.ResolvedValue;

                                    // for simplicity we expect value to be string
                                    var initialValue = resolvedValue!.ToString();

                                    // return new value
                                    context.ResolvedValue = $"{initialValue} {initialValue}";
                                }).Run(fieldDefinition.Resolver ?? throw new InvalidOperationException()));
                    }
                }
            }
        });

        // execute the query
        var result = await Executor.Execute(schema, @"{ name }");

        result.ShouldMatchJson("""
             {
                "data": {
                    "name": "Test Test"
                    }
            }
            """);
    }