Understanding GraphQL for Beginners–Part Three

In Part 2 of Understanding GraphQL for Beginners, we created queries that fetched us data. In Part 3, we learn what are mutations and create mutation queries to modify data. Before we begin, let’s recap what we learned so far in this series:

  • GraphQL is a data manipulation and query language for APIs.
  • There’s no more over and under fetching of data.
  • Root fields define the structure of your response fields based on the object fields selected. They’re the entry points (similar to endpoints) to your GraphQL server.
  • Object fields are attributes of an object.

Learning Outcomes

  • Create a GraphQL mutation to modify data in the database.
  • Use a GraphQL mutation to create a new ActiveRecord.
  • Modify data using a GraphQL mutation.
  • Use a GraphQL mutation to destroy an existing ActiveRecord.

Before You Start

We’re using the same repository as Part 2 for this tutorial. As a reminder, the repository is set up with models and gems needed for GraphQL.

The following models are

Food

Attribute Type
id Bigint
name String
place_of_origin String
image String
created_at Timestamp
updated_at Timestamp

 

Nutrition

Attribute Type
id Bigint
food_id Bigint
serving_size String
calories String
total_fat String
trans_fat String
saturated_fat String
cholesterol String
sodium String
potassium String
total_carbohydrate String
dietary_fiber String
sugars String
protein String
vitamin_a String
vitamin_c String
calcium String
iron String
created_at Timestamp
updated_at Timestamp

What Are Mutations?

Mutations are queries that create, modify, or delete objects in your database, similar to a PUT, POST, or DELETE request in REST. Mutation requests are sent to the same endpoint as query requests. Mutation queries have the following structure:

  • The query starts with mutation.
  • Any required arguments are under input.
  • The mutation field name contains the action it’s trying to perform, that is foodCreate.

We’re naming our mutation query with an object first, followed by the action. This is useful to order the mutations alphabetically, as seen below.

Ordered by object first Ordered by action first
food_create.rb create_food.rb
food_delete.rb create_nutrition.rb
fiid_update.rb delete_food.rb
nutrition_create.rb delete_nutrition.rb
nutrition_delete.rb update_food.rb
nutrition_update.rb update_nutrition.rb
Left: Naming a mutation with an object first, followed by the action. Right: Naming a mutation with the action first, followed by an object.

There’s no preference with which naming convention you go with, but, we’re using the naming convention used on the left side of the image. You can find all mutations under the mutations directory and mutation_type.rb under the types directory.

Creating Your First Mutation Query

We create a foodCreate mutation to create new food items. To create a mutation query, enter the following in your terminal: rails g graphql:mutation foodCreate

The rails generator does the following things:

  1. Check if a new mutation file like base_mutation.rb and mutation_type.rb exists. If it doesn’t, create them.
  2. Add the root field, food_create to mutation_type.rb.
  3. Create a class called food_create.rb.

Let’s go to the mutation_type.rb class and remove the field and method called test_field.

Notice how we don’t need to write a method here like in query_type.rb. The mutation: Mutations::foodCreate executes a method called resolve in that mutation class. We’ll learn what the resolve method is soon. We then go to food_create.rb and your class looks like this:

The first thing we’re going to do is add input arguments. Remove all the comments, then add the following:

GraphQL uses camel case ( placeOfOrigin) by default. To be consistent with Shopify’s style guide, we’ll use a snake case (place_of_origin) instead. The field’s snake case is converted to camel case by GraphQL automatically!

Next, we need to add in a resolve method. The resolve method fetches the data for its field (food_create from mutation_type.rb) and returns a response back. GraphQL server only has one resolve method per field in its schema.

You might be wondering what ** is. It’s an operator called a double splat and it passes in a hash to the resolve method. This allows us to pass in as many arguments as we like. For best practices, if there are more than three parameters, use a double splat to pass in the parameters. For the sake of simplicity, we use the double splat for the three arguments.

We then add in type Types::FoodCreate to indicate our response fields, and inside the resolve method, create a new ActiveRecord.

Now, let’s go test it out on GraphiQL! Go to http://localhost:3000/graphiql to test out our new mutation query!

Write the following query:

When you execute the query, you get the following response.

Try It Yourself #1

Create a mutation called nutritionCreate to create a new Nutrition ActiveRecord. As there are a lot of attributes for the Nutrition class, copy the input arguments from this gist: https://gist.github.com/ShopifyEng/bc31c9fc0cc13b9d7be04368113b49d4

If you want to see the solution, check out nutrition_create.rb as well as its query and response.

Creating the Mutation to Update an Existing Food Item

Create a new mutation called foodUpdate using rails g graphql:mutation foodUpdate. Inside the food_update class, we need to add in the arguments to update. ID will be part of the arguments.

The only required argument here is ID. We need to use an ID to look for an existing product. This allows the resolve method to find the food item and update it.

Next, we write the resolve method and response back.

Let’s test this new mutation query out. We rename our new food item from Apple Pie to Pumpkin Pie.

Try It Yourself #2

Create a mutation called nutritionUpdate to update an existing Nutrition ActiveRecord.

As there are a lot of attributes for the Nutrition class, copy the input arguments from this gist: https://gist.github.com/ShopifyEng/406065ab6c6ce68da6f3a2918ffbeaab.

If you would like to see the solution, check out nutrition_update.rb and the query as well as its query and response.

Creating the Mutation to Delete an Existing Food Item

Create a new mutation called foodDelete using rails g graphql:mutation foodDelete. The only argument needed in food_delete.rb is ID.

Next, we need to add the return type and the resolve method. For simplicity, we just use Types::FoodType as the response.

Let’s test this mutation in GraphiQL.

Try It Yourself #3

Create a mutation called nutritionDelete to delete an existing Nutrition ActiveRecord. Similar to foodDelete, we use Types::NutritionType as the response.

If you would like to see the solution, check out nutrition_delete.rb as well as its query and response.

We’ve reached the end of this tutorial, I hope you enjoyed creating mutations to modify, create or delete data.

Let’s recap what we learned!

  1. Mutations are queries that create, modify, or delete objects in your database.
  2. To generate a mutation, we use rails g graphql:mutation nameAction.
  3. A resolve method fetches the data for its field (food_create from mutation_type.rb) and returns a response back.
  4. GraphQL server only has one resolve method per field in its schema.

GraphQL is a powerful data manipulation and query language for APIs that offers lots of flexibility. At times, it can seem very daunting to implement GraphQL to your application. I hope the Understanding GraphQL for Beginners series helps you to implement GraphQL into your personal projects or convince your work to adopt the GraphQL ecosystem.

If you would like to see the finished code for part three, check out the branch called part-3-solution.

Often mistaken as an intern Raymond Chung is building a new generation of software developers through Shopify’s Dev Degree program. As a Technical Educator, his passion for computer science and education allows him to create bite-sized content that engages interns throughout their day-to-day. When he is not teaching, you’ll find Raymond exploring for the best bubble tea shop.


If building systems from the ground up to solve real-world problems interests you, our Engineering blog has stories about other challenges we have encountered. Visit our Engineering career page to find out about our open positions. Join our remote team and work (almost) anywhere. Learn about how we’re hiring to design the future together - a future that is digital by default.