thelem
thelem

Reputation: 2773

Detecting fields requested in Graphql Hotchocolate query

I have a graphql query that has two fields. They come from separate, slow sources and either or both of them may result in an error, represented as null in this example.

If one or both fields is non-null, then I would like to return the value(s) that I can. If both are null, then I would like to return a GraphQL error. I can do that using a query like so:

[ExtendObjectType(OperationTypeNames.Query)]
public class FooQuery
{
    [GraphQLName("searchFoo")]
    public async Task<Foo> SearchFoo(FooRequest request)
    {
        var foo = new Foo {
            Bar = GetBar(), // Slow, may return null
            Baz = GetBaz()  // Slow, may return null
        }
        if (Bar == null && Baz == null) {
            throw new GraphQLException(...);
        }
        return foo;
    }
}

It may be that the user is only interested in Bar and therefore hasn't included Baz in their request.

Q: Is there a way that I can detect the fields that have been asked for, and shortcut the processing of Baz?

I am aware that this would mean an error response for Bar would result in the whole query returning an error, even if data is actually available for Baz. We've already got clients calling this query, so I'd rather not split it into separate queries as that would require changes in the client code which I do not have control over.

Upvotes: 2

Views: 129

Answers (2)

thelem
thelem

Reputation: 2773

Based on the video by @Michael Ingmar Staib, this can be done in two ways.

Hot Chocolate 13

[ExtendObjectType(OperationTypeNames.Query)]
public class FooQuery
{
    [GraphQLName("searchFoo")]
    public async Task<Foo> SearchFoo(FooRequest request, IResolverContext context)
    {
        var selections = context.GetSelections((ObjectType)context.Selection.Type.NamedType());
        var hasSelectedBaz = selections.Any(t => t.Field.Name.Equals("baz"));
        var foo = new Foo {
            Bar = GetBar(), // Slow, may return null
            Baz = hasSelectedBaz ? GetBaz() : null  // Slow, may return null
        }
        if (Bar == null && Baz == null) {
            throw new GraphQLException(...);
        }
        return foo;
    }
}

Hot Chocolate 14

[ExtendObjectType(OperationTypeNames.Query)]
public class FooQuery
{
    [GraphQLName("searchFoo")]
    public async Task<Foo> SearchFoo(FooRequest request, [IsSelected("baz")] hasSelectedBaz)
    {
        var foo = new Foo {
            Bar = GetBar(), // Slow, may return null
            Baz = hasSelectedBaz ? GetBaz() : null  // Slow, may return null
        }
        if (Bar == null && Baz == null) {
            throw new GraphQLException(...);
        }
        return foo;
    }
}

Upvotes: 1

Michael Ingmar Staib
Michael Ingmar Staib

Reputation: 1927

This can be done with the selections api in Hot Chocolate 14.

Here is a youtube episode that shows how it works. https://youtu.be/XZVpimb6sKg

Upvotes: 1

Related Questions