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.
To download the source code, visit the GraphQL Mutations Source Code.
For the complete navigation of this tutorial visit GraphQL ASP.NET Core Tutorial.
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 that 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(IServiceProvider provider)
:base(provider)
{
Query = provider.GetRequiredService<AppQuery>();
Mutation = provider.GetRequiredService<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.
In the next part of this tutorial, we are going to create an ASP.NET Core Web API application, to consume the GraphQL application that we created until now.
So, see you there.





Hi,
How can we apply validation with for example fluentvalidation, please?
Sanyi
@@disqus_GtEeIZUUDN:disqus I’m looking to use GraphQL in an ASP.NET Web API application. We plan on all queries being handled by GraphQL. Our UI is Angular.
All POST and PUT operations need to be handled by Web API controllers because our business logic and workflows are super complex, which is why we don’t want to use GraphQL Mutations. Actually, we will be using MediatR for all commands.
What is your recommendation for POST and PUT operations that would typically return an update object back to the caller after the database insert or update has taken place.
I’m asking because GraphQL removes the need for many DTO objects in the code base. So we would have to create DTO objects for each POST and PUT to return. Or, do you recommend that after a POST or PUT, the Angular application use GraphQL to requery the data if required.
Thank you very much. Really like the Ultimate ASP.NET Core 3 Web API.
Karl
Hello Karl. First of all, I am so glad you are enjoying our book, we really invested a lot of time and knowledge into it. So, hearing something like that from the reader is always the best thing.
About your question. My personal opinion is if you don’t have to use more than one request to accomplish something, don’t do it. That said, if you are using Web API to handle these POST and PUT requests, I would create required DTOs and send them back in a same request. Again, this is what I would do if I had to mix GraphQL and Web API logic (but I never did that 😀 ).
@disqus_GtEeIZUUDN:disqus thank you. Great news, I’ve learned the Mutations and added them to my project. Way awesome! Thank you for your guidance and coaching. I’ll post a link to my blog post when I publish it.
Best regards,
Karl
Amazing content! Thank you for these examples. They helped a lot! Official documentation only includes the “create” part.
You are very welcome. I’m glad you enjoyed it. I hope you will find more good stuff on our site. Best regards and see you again 🙂
Thanks very much for your constribution. It saves me a lot of time for my learning curve.
Respectfully yours.
Tam
Thank you too mate. Have a great day. Best regards.