From Query to Mutation with GraphQL.Conventions and ASP.NET Core

Wouter Huysentruit
5 min readNov 5, 2018

Introduction

In this post we will see how to create a GraphQL endpoint with GraphQL.Conventions and ASP.NET Core 2.1. We will cover creating a project from scratch until the point where we add our own queries and mutations.

In GraphQL, a query is a request for data, while a mutation is a request to change data. That change data could be anything from CRUD (Create, Update, Delete) to commands (CQRS anyone?). All types, queries and mutations are described in a so called schema.

What is GraphQL.Conventions?

GraphQL.Conventions is a library that sits on top of the GraphQL .NET library. The GraphQL.Conventions library takes away the need to create/maintain your own schema definition and generates the schema by convention.

The library is open-source, licensed under the MIT license and available on GitHub. A ready to use package is also available on NuGet.

Prerequisites

Before getting started, make sure you have the .NET Core 2.1 SDK installed on your system. If not, install .NET Core 2.1 SDK from this page.

To verify which version you have installed, run dotnet --version, which should output something like 2.1.403.

Creating a new project

Create a new folder and open a console window (terminal or cmd) into that folder and type the following command:

dotnet new webapi --name GraphApp

This command will scaffold a new ASP.NET Core Web API project, named GraphApp.csproj, into the GraphApp folder.

Before we continue, let’s start the application to verify all prerequisites are met by typing these commands in the console:

cd GraphApp
dotnet run

Now, open the browser and browse to https://localhost:5001/api/values, you should get back ["value1","value2"]. Go back to the console and terminate the dotnet process by pressing Ctrl+C.

Setting up GraphQL.Conventions

Adding the NuGet package

In the console, type:

dotnet add package GraphQL.Conventions

When using Visual Studio, you can install the package from the Package Manager Console like this:

PM> Install-Package GraphQL.Conventions

Preparing the query, mutation and user context object

Before actually adding queries and mutations, we will create three empty classes: Query, Mutation and UserContext, so we can continue with the rest of our setup.

Creating an implementation for IDependencyInjector

GraphQL.Conventions uses dependency injection (DI) but is not bound to a specific framework. This means we need to add a little implementation to glue the DI framework we’re using in our project. In our case, this is Microsoft.Extensions.DependencyInjection.

Injector.cs

Configuring Startup.cs

Having all our (empty) classes in place, we have to register some required services by modifying the ConfigureServices method in Startup.cs:

Startup.cs

Creating the API controller

The API controller hosts our GraphQL endpoint at the route /api/graph. This route accepts POST requests with a GraphQL formatted request in the body.

GraphController.cs

Testing the GraphQL endpoint

Testing a GraphQL endpoint is best done with a GraphQL client like GraphiQL (mind the i). For our tests, we have used the Electron based client, which can be downloaded from here. For more information about GraphiQL see the post by Clay Allsopp.

Once the client is installed, it’s time to start our application as usual:

dotnet run

Now, start the GraphiQL client and enter the GraphQL Endpoint URL of our application, which is: https://localhost:5001/api/graph. When expanding the Docs panel on the right, you should find documentation for an empty Query and empty Mutation object which perfectly reflects our empty Query and Mutation classes in code.

Writing our first mutation

In-memory repository

For demonstration purposes, we will add a model and in-memory repository for storing TODOs:

TodoRepository.cs

Register the repository in Startup.cs by adding this line to the ConfigureServices method:

services.AddScoped<ITodoRepository, TodoRepository>();

Add a GraphQL todo type

In our repository, we have a TodoModel type, but for GraphQL, we will add an additional Todo type and map from one to the other. The reason for using a separate type for GraphQL is because we want to annotate the class and its properties with GraphQL.Conventions specific attributes, like [Description].

Todo.cs

Mapping a database entity or service model to the GraphQL model can be done manually or by using a framework like AutoMapper.

Adapt the mutation class

Open Mutation.cs and add a method for adding TODOs to the in-memory repository:

Mutation.cs

The AddTodo method itself takes two parameters: ITodoRepository repository will be injected by GraphQL.Conventions because of the [Inject] attribute, while NonNull<string> description will become a mutation parameter. NonNull<> is a decorator, telling GraphQL.Conventions that this field is required.

In our example, the mutation input parameter is a string. This can as well be a class, in which case the class must be decorated with the [InputType] attribute. A class marked with [InputType] can be used as a query or mutation input type, not as a return/result type.

Testing the AddTodo mutation

Start the application and go to the GraphiQL client. In the GraphiQL client, press Ctrl+R to reload the schema. When we now check the mutation in the documentation, we should see the addTodo mutation being mentioned.

In the left window of GraphiQL, add a test mutation to add a TODO item:

mutation AddTodo {
addTodo(description: "Do the dishes") {
id
description
}
}

Execute this mutation by clicking the Execute Query ( ▶) button. If all goes well, a response like this should appear in the output window:

{
"data": {
"addTodo": {
"id": "78081912-ec8e-4486-8326-3c23bb3c8fad",
"description": "Do the dishes"
}
}
}

That’s it. We have added a TODO in our in-memory repository by executing a GraphQL mutation!

Writing our first query

In the previous step, we’ve learned how to add TODOs to the in-memory repository. In this step, we will create a query to get all TODOs at once and a query to only get a single TODO.

Adapt the query class

Open the Query.cs and add the methods for querying the data:

Query.cs

Testing the queries

Again, start the application and go to the GraphiQL client. In the GraphiQL client, press Ctrl+R to reload the schema. When we now check the query in the documentation, we should see the todo and todos queries being mentioned.

In the left window of GraphiQL, add two additional queries:

query All {
todos {
id
description
}
}
query One {
todo(id: "abdbb6f9-ff50-4ea0-8c1b-24a4066b40ae") {
id
description
}
}

Execute the All query by clicking the Execute Query ( ▶) button and selecting All. A response like this should appear in the output window:

{
"data": {
"todos": []
}
}

The empty array means no TODOs were added to the in-memory repository. Add some by using the mutation created in the previous step and run this query again.

Voila! That’s all there is to it.

Wrapping up

In this post we have seen how to create our own GraphQL endpoint and how to add queries and mutations with documented type definitions.

The complete source code of the project created in this post can be found here.

--

--

Wouter Huysentruit

Software Engineer and Architect focusing on .NET and Microsoft technologies. Microsoft MVP. Practitioner of clean code. #solid #tdd #ddd #cqrs #es #graphql