Search  
Always will be ready notify the world about expectations as easy as possible: job change page
Aug 13, 2019

GraphQL Mutations in ASP.NET Core (POST, PUT, DELETE Actions)

Author:
Marinko Spasojevic
Source:
Views:
1167

GraphQL mutations are actions which we use to Add, Update and Delete data from a database. Until now, we have been executing only GraphQL Queries (fetching data) but in this article, we are going to talk more about data mutations in GraphQL.

Input Types and Schema Enhancing for the GraphQL Mutations

Let’s start with creating a new class OwnerInputType inside the Types folder:

public class OwnerInputType : InputObjectGraphType
{
    public OwnerInputType()
    {
        Name = "ownerInput";
        Field<NonNullGraphType<StringGraphType>>("name");
        Field<NonNullGraphType<StringGraphType>>("address");
    }
}

This is the type which we are going to send from a client as an argument for our mutations. As we can see, this class derives from the InputObjectGraphType class and not from the ObjectGraphType as before.

In the constructor, we just populate the Name property and create two fields. We can see that we don’t have the Id and Accounts properties because we don’t need them for the mutations.

If we can recall the starting article of this series, there we can see that for the queries we had to create the AppQuery class. Well, it is the same for mutations, just we are not going to create the AppQuery class but the AppMutation class inside the GraphQLQueries folder:

public class AppMutation : ObjectGraphType
{
    public AppMutation()
    {
    }
}

Finally, we need to enhance our Schema class, with the Mutation property: 

public class AppSchema : Schema
{
    public AppSchema(IDependencyResolver resolver) : base(resolver)
    {
        Query = resolver.Resolve<AppQuery>();
        Mutation = resolver.Resolve<AppMutation>();
    }
}

Excellent. We are ready to create some mutations in our project.

Create Mutation

Let’s start with the IOwnerRepository interface modification:

public interface IOwnerRepository
{
    IEnumerable<Owner> GetAll();
    Owner GetById(Guid id);
    Owner CreateOwner(Owner owner);
}

We see that the CreateOwner method returns a newly created owner object, which is quite common in GraphQL.

Now, we can add the CreateOwner method inside the OwnerRepository class:

public Owner CreateOwner(Owner owner)
{
    owner.Id = Guid.NewGuid();
    _context.Add(owner);
    _context.SaveChanges();
    return owner;
}

Finally, we can modify the AppMutation class:

public class AppMutation : ObjectGraphType
{
    public AppMutation(IOwnerRepository repository)
    {
        Field<OwnerType>(
            "createOwner",
            arguments: new QueryArguments(new QueryArgument<NonNullGraphType<OwnerInputType>> { Name = "owner" }),
            resolve: context =>
            {
                var owner = context.GetArgument<Owner>("owner");
                return repository.CreateOwner(owner);
            }
        );
    }
}

So, we create a field to return the OwnerType object, with the „createOwner“ name, a single argument of the OwnerInputType type and with the resolve action which is going to execute the CreateOwner method from our repository.

And that is it.

Let’s start our project, open Playground and send a request: 

 

So, instead of the query keyword, we use the mutation keyword for mutations. And this is the only new difference. We have an argument, a call to the createOwner mutation and the fields that we require as a part of the result. On the Playground’s right side, we can see that the creation has been successful and we have a new Owner object returned.

Awesome, now we can continue on.

Update Mutation

As we did in a previous section of this article, we are going to start with IOwnerRepository modification:

public interface IOwnerRepository
{
    IEnumerable<Owner> GetAll();
    Owner GetById(Guid id);
    Owner CreateOwner(Owner owner);
    Owner UpdateOwner(Owner dbOwner, Owner owner);
}

Let’s move on to the OwnerRepository file:

public Owner UpdateOwner(Owner dbOwner, Owner owner)
{
    dbOwner.Name = owner.Name;
    dbOwner.Address = owner.Address;

    _context.SaveChanges();

    return dbOwner;
}

Lastly, we have to add an additional field in a constructor of the AppMutation class:

Field<OwnerType>(
    "updateOwner",
    arguments: new QueryArguments(
        new QueryArgument<NonNullGraphType<OwnerInputType>> { Name = "owner" },
        new QueryArgument<NonNullGraphType<IdGraphType>> { Name = "ownerId" }),
    resolve: context =>
    {
        var owner = context.GetArgument<Owner>("owner");
        var ownerId = context.GetArgument<Guid>("ownerId");

        var dbOwner = repository.GetById(ownerId);
        if (dbOwner == null)
        {
            context.Errors.Add(new ExecutionError("Couldn't find owner in db."));
            return null;
        }

        return repository.UpdateOwner(dbOwner, owner);
    }
);

Excellent. It is time to test this:

Everything is working as it supposed to.

Let’s move on. 

Delete Mutation

Following the same pattern, let’s modify the interface first:

public interface IOwnerRepository
{
    IEnumerable<Owner> GetAll();
    Owner GetById(Guid id);
    Owner CreateOwner(Owner owner);
    Owner UpdateOwner(Owner dbOwner, Owner owner);
    void DeleteOwner(Owner owner);
}

Then, let’s continue with the OwnerRepository modification:

public void DeleteOwner(Owner owner)
{
    _context.Remove(owner);
    _context.SaveChanges();
}

The last thing we need to do is to modify AppMutation file:

Field<StringGraphType>(
    "deleteOwner",
    arguments: new QueryArguments(new QueryArgument<NonNullGraphType<IdGraphType>> { Name = "ownerId" }),
    resolve: context =>
    {
        var ownerId = context.GetArgument<Guid>("ownerId");
        var owner = repository.GetById(ownerId);
        if (owner == null)
        {
            context.Errors.Add(new ExecutionError("Couldn't find owner in db."));
            return null;
        }

        repository.DeleteOwner(owner);
        return $"The owner with the id: {ownerId} has been successfully deleted from db.";
    }
);

And let’s test this as well:

You can send a query to fetch all the owners and see for your self that this owner entity is not in the database anymore.

Conclusion

There we go, all the mutations are completed now.

Now we know, how to use Input type files for the mutations, how to create different mutation actions and how to create mutation requests from a client side.

Send message
Type
Email
Your name
*Message