Bind resolvers

Resolvers are used to resolve the data for the query, or execute mutations. They bind the execution of GraphQL operation into your logic.

See also

Bind using SchemaBuilder

When building the executable schema using Build the SchemaBuilder takes an IResolverMap and/or ISubscriberMap values. These maps include the resolvers for fields of object types.

  • Simplest form of a resolver is an delegate returning a value.

    [Fact]
    public async Task Part2_BindResolvers_ReturnValue()
    {
        // Create builder and load sdl
        var builder = new SchemaBuilder()
            .Add(@"
                type Query {
                    name: String
                }
                ");

        // Build schema with the resolver
        var schema = await builder.Build(new SchemaBuildOptions
        {
            Resolvers = new ResolversMap
            {
                {
                    "Query", "name", () => "Test"
                }
            }
        });

        // Quickest but least configurable way to execute 
        // queries against the schema is to use static
        // execute method of the Executor
        var result = await Executor.Execute(schema, @"{ name }");

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

  • Use ResolverContext: context provides information about the query being executed.

    [Fact]
    public async Task Part2_BindResolvers_UseContext()
    {
        // Create builder and load sdl
        var builder = new SchemaBuilder()
            .Add(@"
                type Query {
                    name: String
                }
                ");

        // Build schema with the resolver
        var schema = await builder.Build(new SchemaBuildOptions
        {
            Resolvers = new ResolversMap
            {
                {
                    "Query", "name", (ResolverContext context) =>
                    {
                        context.ResolvedValue = "Test";
                        return default;
                    }
                }
            }
        });

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

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

  • You can access properties of the ResolverContext by named parameters keeping the resolver simple. In this case we access the value of the parent called objectValue.

    [Fact]
    public async Task Part2_BindResolvers_ObjectValue()
    {
        // Create builder and load sdl
        var builder = new SchemaBuilder()
            .Add("""
                type Query {
                    vader: Parent
                }

                type Parent {
                    luke: String
                }
                
                """);

        // Build schema with the resolvers
        var schema = await builder.Build(new SchemaBuildOptions
        {
            Resolvers = new ResolversMap
            {
                {
                    "Query", "vader", () => "I am your father"
                },
                {
                    "Parent", "luke", (string objectValue) => $"Luke, {objectValue}"
                }
            }
        });


        var result = await Executor.Execute(schema, @"{ vader { luke }}");

        result.ShouldMatchJson("""
            {
              "data": {
                "vader": {
                    "luke": "Luke, I am your father"
                }
              }
            }
            """);
    }

  • For complex scenarios usage of ResolversBuilder is recommended

    [Fact]
    public async Task Part2_BindResolvers_ResolversBuilder()
    {
        // Create builder and load sdl
        var builder = new SchemaBuilder()
            .Add("""
                type Query {
                    vader: Parent
                }

                type Parent {
                    luke: String
                }
                
                """);

        // Build schema with the resolvers
        var schema = await builder.Build(new SchemaBuildOptions
        {
            Resolvers = new ResolversBuilder()
                .Resolvers("Query", new Dictionary<string, Action<ResolverBuilder>>()
                {
                    ["vader"] = b => b
                    // use middleware to modify the ResolvedValue    
                    .Use(next => async context =>
                    {
                        await next(context);
                        context.ResolvedValue = $"------ {context.ResolvedValue}";
                    })
                    // this is the the actual resolver
                    .Run(() => "I am your father"),
                })
                .Resolvers("Parent", new Dictionary<string, Action<ResolverBuilder>>()
                {
                    ["luke"] = b => b.Run((string objectValue) => $"Luke, {objectValue}")
                })
                .BuildResolvers()
        });


        var result = await Executor.Execute(schema, @"{ vader { luke }}");

        result.ShouldMatchJson("""
            {
              "data": {
                "vader": {
                    "luke": "Luke, ------ I am your father"
                }
              }
            }
            """);
    }