Search code examples
graphql-dotnet

Build hierarchical object tree in GraphQL.NET


I am building an API that allows you to fetch a hierarchical object tree in GraphQL. These objects are not in a data store but come from some upstream API. For example;

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string Surname { get; set; }
    public int ManagerId { get; set; }
}

I want to replace the ManagerId property with an actual Employee object referring to the manager. I got this far;

class EmployeeType : ObjectGraphType<Employee>
{
    Field(x => x.Id);
    Field(x => x.FirstName);
    Field(x => x.Surname);

    Field<EmployeeType>(
        "manager",
        arguments: new QueryArguments(new QueryArgument<IdGraphType> { Name = "id" }),
        resolve: context =>
        {
            int id = context.GetArgument<int>("id");
            return GetEmployeeById(id);
        });
}

The idea is that there is a custom resolver for the manager that will go and fetch it from the API. The problem is that the person calling this API would need to pass in the ID explicitly, like this;

POST /employees
{
  Employee(id: 1234) {
    id,
    firstName,
    lastName,
    manager(id: 5432) {
      firstName,
      lastName
    }
  }
}

This doesn't work because they would first need to know what the manager's ID is before they can execute this query. How can I execute this GraphQL query in stages, where I first get the employee object, then fetch the manager object once I know his or her ID? Additionally, how do I pass down the context of the parent into the resolver so that it can get hold of the ID property?


Solution

  • I found the answer! I can get hold of the parent using the Source property. Now I don't need to specify any arguments for EmployeeType in the resolver; I can just do this:

        Field<EmployeeType>(
            "manager",
            resolve: context =>
            {
                int id = context.Source.ManagerId;
                return GetEmployeeById(id);
            });