Some more advanced GraphQL concepts with HotChocolate - Part 4

In this article, we will explore how data can be modified using GraphQL.

In the previous post, we discussed the Query type and emphasized that it is a built-in root type defined in the GraphQL specification. Now, we will delve into another native root type: the Mutation type.

What is the Mutation type ?

If we aim to create an API endpoint that modifies data, such as inserting data into a database, we must designate this endpoint as a Mutation rather than a Query. It's as straightforward as the following snippet demonstrates.

1type Mutation {
2  CreateCustomer(name: String, age: Float): Customer
3  EditCustomer(id: ID!, name: String, age: Float): Customer
4}

That's it! We simply specify that there are two methods available for altering a customer: one for creating a customer and another for modifying an existing customer.

It's worth noting a point, however: our example is quite simple, consisting of only a customer with three fields. In real-world scenarios, objects are likely to have many more properties, resulting in methods with similar arguments.

1type Mutation {
2  CreateObject(arg1: String, arg2: Float, ..., arg15: String): Object
3  EditObject(id: ID!, arg1: String, arg2: Float, ..., arg15: String): Object
4}

Therefore, if a property is added to the object (e.g., arg16 in our case), it must be propagated to all corresponding methods, leading to a potentially error-prone, cumbersome and time-consuming process. That's precisely why the GraphQL specification provides us with the capability to define input types, enabling us to consolidate elements that can be reused elsewhere. In SDL, it can be done as follows.

1input CustomerInput {
2  name: String
3  age: Float
4}
5
6type Mutation {
7  CreateCustomer(input: CustomerInput): Customer
8  EditCustomer(id: ID!, input: CustomerInput): Customer
9}

How to perform a request ?

A request for a mutation can be executed in a manner similar to a query request, as illustrated below. It is executed against the same endpoint (/graphql).

 1POST http://<path_api>/graphql
 2{
 3    mutation {
 4      CreateCustomer(input: { name: "Linda Price", age: 25 }) {
 5        customer {
 6          id	  
 7        }
 8      }
 9    }
10}

Here, we attempt to create a customer and retrieve the newly created customer along with its ID.

How is SDL integrated with HotChocolate ?

Information

This implementation is entirely specific to HotChocolate, and other libraries may implement mutations differently.

  • Add two new methods to the ICustomerRepository interface.
1public interface ICustomerRepository
2{
3    // ...
4    Customer CreateCustomer(Customer customer);
5    Customer EditCustomer(Customer customer);
6}
  • Implement the corresponding methods in the concrete MockCustomerRepository class.
 1public class MockCustomerRepository : ICustomerRepository
 2{
 3    public Customer CreateCustomer(Customer customer)
 4    {
 5        customer.Id = Guid.NewGuid().ToString();
 6        return customer;
 7    }
 8	
 9    public Customer EditCustomer(Customer customer)
10    {
11        return customer;
12    }
13}
  • Create a Mutation.cs class and add the following code to it.
 1
 2public class CustomerInput
 3{
 4    public string Name { get; set; }
 5
 6    public int Age { get; set; }
 7}
 8
 9public class Mutation
10{
11    public Customer CreateCustomer([Service] ICustomerRepository customerRepository, CustomerInput input)
12    {
13        var customer = new Customer() { Name = input.Name, Age = input.Age };
14        return customerRepository.CreateCustomer(customer);
15    }
16	
17    public Customer EditCustomer([Service] ICustomerRepository customerRepository, string id, CustomerInput input)
18    {
19        var customer = new Customer() { Id = id, Name = input.Name, Age = input.Age };
20        return customerRepository.EditCustomer(customer);
21    }
22}
  • Modify the StartUp class to instruct the server to adhere to the GraphQL specification.
 1public class StartUp : FunctionsStartup
 2{
 3    public override void Configure(IFunctionsHostBuilder builder)
 4    {
 5        ConfigureServices(builder.Services);
 6    }
 7
 8    private static void ConfigureServices(IServiceCollection services)
 9    {
10        // ...
11        
12        services.AddGraphQLFunction().AddMutationType<Mutation>();
13    }
14}

Consuming the service

We will now transition to the client project.

  • Add an indexMutation.html file and fill it with the following code.
 1<html>
 2<head>
 3    <title>GraphQL</title>
 4</head>
 5<body>
 6    <pre><code class="language-json" id="code"></code></pre>
 7    <script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.9/beautify.min.js"></script>
 8    <script>
 9        (async function () {
10            const data = JSON.stringify({
11                 query: `mutation {
12                            createCustomer(input: {name:"Melinda Price", age: 25}) {        
13                                id    
14                            }
15                       }`
16            });
17
18            const response = await fetch(
19                'http://localhost:7132/api/graphql',
20                {
21                    method: 'post',
22                    body: data,
23                    headers: {
24                        'Content-Type': 'application/json'
25                    },
26                }
27            );
28
29            const json = await response.json();
30            document.getElementById('code').innerHTML = js_beautify(
31                JSON.stringify(json.data)
32            );
33        })();
34    </script>
35</body>
36</html>
Important 1

Please exercise caution as the case sensitivity of JavaScript code is crucial. For instance, although a method may be named CreateCustomer in C# code, it must be referenced as createCustomer in JavaScript.

Important 2

Similar to other libraries, HotChocolate provides a straightforward tool for testing GraphQL queries, allowing users to swiftly determine if a query is properly structured and functional. This tool can be accessed through /api/graph, where "path" represents the domain name of the server.

  • Run the program

That concludes our discussion on the Mutation type. In the next post, we will explore how a GraphQL server can manage filtering.

Advanced GraphQL concepts with HotChocolate - Part 5