Sune Monrad
Sune Monrad

Reputation: 186

How to access arguments in nested fields in ASP.NET Core GraphQL

I have a query with the field "statistics" which is a sub-query with three different accumulated values. I would like to be able to give statistics a country argument and then access that argument in the resolvers for the different fields in the sub-query.

I'm using the GraphQL.Server.Transports.AspNetCore nuget package. The sub query is resolved using the IDependencyResolver since it has some dependencies to services that are used in the resolver for the different field.

I've tried to access the parent through the ResolveFieldContext but it doesn't seem to be available. There is a property on the context called "Source" but that is referring to the sub query object.

It seems that it should be possible if we look at other implementations of GraphQL but I have no clue how the get the result from ASP.NET Core

The code below shows a part of the main Query called "CompanyGroupQuery"

Field<CompanyStatisticsQuery>(
                "statistics",
                arguments: new QueryArguments(new QueryArgument<StringGraphType> { Name = "country" }),
                resolve: context => resolver.Resolve<CompanyStatisticsQuery>()                
            );

The sub-query look like this

Field<IntGraphType>(
                "completeInvoicesCount",
                resolve: context => {
                    // This is to show what I'm trying to achieve
                    var parent = context.Parent;
                    var companyId = context.GetArgument<string>("companyId");
                    var country = context.GetArgument<string>("country");

                    return null;

                }
            );

Upvotes: 3

Views: 2322

Answers (2)

Daniel
Daniel

Reputation: 9524

Here's an example of SUNMO's answer with some descriptive comments:

// This is an internal object whose properties don't necessarily need to be
// exposed as GraphQL fields. It's purpose is to propagate arguments or some
// partially resolved data which can be further resolved in a child GraphType.
public class Statistics
{
    public string CompanyId { get; set; }
    public string Country { get; set; }
}

// This is the root GraphQL Query class.
public class MyQuery : ObjectGraphType
{
    private const string CompanyIdArgumentName = "companyId";
    private const string CountryArgumentName = "country";

    public MyQuery()
    {
        Field<CompanyStatisticsType>(
            name: "statistics",
            arguments: new QueryArguments(
                new QueryArgument<StringGraphType> { Name = CompanyIdArgumentName },
                new QueryArgument<StringGraphType> { Name = CountryArgumentName }
            ),
            resolve: context => {
                return new Statistics
                {
                    CompanyId = context.GetArgument<string>(CompanyIdArgumentName),
                    Country = context.GetArgument<string>(CountryArgumentName)
                };
            }
            // In the above `resolve` implementation, we're passing the value
            // of the arguments to the a new Statistics object which will be
            // CompanyStatisticsType's context.Source
        );
    }
}

public class CompanyStatisticsType : ObjectGraphType<Statistics>
{
    public CompanyStatisticsType()
    {
        Field<IntGraphType>(
            name: "completeInvoicesCount",
            resolve: context => {
                return GetCompletedInvoicesCount(
                    companyId: context.Source.CompanyId,
                    country: context.Source.Country
                    // Above we are using context.Source, which is an
                    // instance of the `Statistics` class.
                );
            }
        );

        Field(statistics => statistics.Country);
        // Notice how we expose the above `country` field but not `companyId`,
        // further demonstrating that not every property on the `Statistics`
        // class needs to be exposed as a GraphQL field.
    }
}

Upvotes: 5

Sune Monrad
Sune Monrad

Reputation: 186

I found a solution for this problem in case anyone is interested. Instead of trying to access the parent directly create a class which the query can inherit from. In this case I created a statistics class which contained a property for the country code. The property is then populated in the statistics field resolver and a new object of type Statistics is returned with that value. I'm then able to access the country code from the sub-query by looking at context.Source.Country and then I simply don't map the country property to a field in the sub-query since I'm not interested in exposing it.

Upvotes: 2

Related Questions