GraphQL using .NET Boxed: Mutations

This post is going to continue my exploration of GraphQL using the .NET Boxed template as a jumping off point. The code I am starting with can be found here. Check out GraphQL using .NET Boxed: Queries from last week for an exploration of queries.

Mutations are GraphQL’s way of allowing a client to request changes to the data on the server-side.

Starting Point

As we discovered last week, MainSchema is the central point to finding how GraphQL is set up in this template. Just for reference here is the full class.

public class MainSchema : Schema
{
    public MainSchema(
        QueryObject query,
        MutationObject mutation,
        SubscriptionObject subscription,
        IDependencyResolver resolver)
        : base(resolver)
    {
        this.Query = resolver.Resolve<QueryObject>();
        this.Mutation = mutation;
        this.Subscription = subscription;
    }
}

We are interested in the Mutation property which is being assigned a MutationObject.

Mutation Object

The following is the full MutationObject class which defines what mutations are allowed for which objects on this server and what happens when a mutation request is received.

public class MutationObject : ObjectGraphType<object>
{
    public MutationObject(IHumanRepository humanRepository)
    {
        this.Name = "Mutation";
        this.Description = "The mutation type for updates to our data.";
        this.FieldAsync<HumanObject, Human>(
            "createHuman",
            "Create a new human.",
            arguments: new QueryArguments(
                new QueryArgument<NonNullGraphType<HumanInputObject>>()
                {
                    Name = "human",
                    Description = "The human you want to create.",
                }),
            resolve: context =>
            {
                var human = context.GetArgument<Human>("human");
                return humanRepository.AddHuman(human,
                                                context.CancellationToken);
            });
    }
}

This is very similar to have the QueryObject from last week was set up. The first big difference is in the QueryArguments. The mutation is taking a HumanInputObject class instead of an ID. If you look at the query argument you will also see that this argument isn’t allowed to be null.

new QueryArgument<NonNullGraphType<HumanInputObject>>()

What is the HumanInputObject class? It is an InputObjectGraphType and defines the shape of what the mutation query argument looks like. As you can see in the following it provides a name, description, and list of fields.

public class HumanInputObject : InputObjectGraphType
{
    public HumanInputObject()
    {
        this.Name = "HumanInput";
        this.Description = "A humanoid creature from Star Wars.";
        this.Field<NonNullGraphType<StringGraphType>>(nameof(Human.Name));
        this.Field<StringGraphType>(nameof(Human.HomePlanet));
        this.Field<ListGraphType<EpisodeEnumeration>>(nameof(Human.AppearsIn), "Which movie they appear in.");
    }
}

Also, note that the fields are using nameof on the properties of the Human class to make sure the names match which will prevent any problems with the mapping between the 3 different human classes this project is working with. Here is an example of the field definition pulled out from the above sample.

this.Field<NonNullGraphType<StringGraphType>>(nameof(Human.Name));

Another thing to make note of is that even at the field level you can set if a field is allowed to be null or not on top of setting the type of the field.

Back over in the MutationObject let’s look at the resolve inside of the FieldAsync call.

resolve: context =>
{
    var human = context.GetArgument<Human>("human");
    return humanRepository.AddHuman(human, context.CancellationToken);
});

This is pulling the human query argument and it is being translated into an instance of the Human class and then sent to the repository to be saved.

Wrapping Up

That covers the basic exploration of mutations. I’m thinking about looking at subscriptions.

The associated sample code can be found here.


Also published on Medium.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.