Ruby on Rails GraphQL API Tutorial: Creating Data with Mutations
Tags: rails, graphql, api, tutorial
Published: 2019-09-22 20:15:13

---
title: "Ruby on Rails GraphQL API Tutorial: Creating Data with Mutations"
published: true
description: a tutorial for creating a simple graphql api in rails
tags: rails, graphql, api, tutorial
series: "Ruby on Rails GraphQL API Tutorial"
---

Continuing from the last installment, we're going to introduce the other type of request in GraphQL: **Mutations.**

Mutations allow us to create, update, or destroy data in our database. Paired with the Query's ability to read data, we now have a full set of CRUD actions!

In this tutorial, we will focus on building a simple mutation to create a new `Order` record in our database.

**Once again, this tutorial is largely adapted from [this AMAZING tutorial by Matt Boldt](https://mattboldt.com/2019/01/07/rails-and-graphql/)**. Thanks again, Matt!!



# Overview 
In this second article, we'll go through the steps to:
* create the needed Mutation files
* create our first mutation (add a new `Order` to the database)
* add routing to `/app/graphql/types/mutation_type.rb`
* write and execute our first GraphQL Mutation in [Insomnia](https://insomnia.rest/)

Let's dive in!


# What is a GraphQL Mutation?

From the [GraphQL docs](https://graphql.org/learn/queries/):

>Most discussions of GraphQL focus on data fetching, but any complete data platform needs **a way to modify server-side data** as well.

*(Emphasis mine)*

Mutations are exactly that--a request that modifies (creates, updates, destroys) data in the database. 


### GraphQL mutation format

Similar to Queries, this is what our first GraphQL mutation will look like:

```graphql
mutation {
  createOrder(input: {
    description: "Octo Octa - Resonant Body (vinyl)",
    total: 21.82
  }) {
    order {
	  id
      description
      total
      payments {
        id
        amount
      }
      paymentsCount
    }
    errors
  }
}
```
Several things to notice: 

* At the very top, we define our request as a `mutation` instead of `query`--this is necessary for routing the request correctly, which we'll cover below
* `createOrder` is the name we will give to our mutation, and we call it like a function with the arguments inside parentheses: `createOrder( input: {} )`
* the mutation accepts `input`, structured as a hash, where we pass a string for `description` and a float for `amount` (we can set these inputs to optional, or make them required)
* following the closing parentheses from `createOrder()`, we add another hash to outline the data we want to return from the mutation
	* notice that it looks **essentially the same as our first query**, except that we also return `errors` along with the new `order` we created
	* this return is **optional**, but it is a good idea--you can both mutate the database AND query the data in one atomic operation, which is very efficient!

Okay, now that we know what our mutation request is going to *look like*, let's actually build out the code!


# Adding mutations to our /app/

Navigate to the `/app/graphql/mutations` directory, and you'll notice it's empty (except for that empty `.keep` file). Right now, our app does not have any mutations. To add them in, we'll need to do a few things:

1. Create a `BaseMutation` class for our mutations to inherit from
2. Create a specific mutation (`createOrder`) which inherits from `BaseMutation`
3. Add routing to `/app/graphql/types/mutation_type.rb` (much like we did with `/app/graphql/types/query_type.rb` in the previous article)

After that, we can repeat steps 2 and 3 for each new mutation we want to add!

# Creating a mutation

### Create new file `/app/graphql/mutations/base_mutation.rb`
Let's create a base type for our other mutations to inherit from. Create a new `base_mutation.rb` file in the (mostly) empty `/app/graphql/mutations` directory, and add this code:

```ruby
# /app/graphql/mutations/base_mutation
class Mutations::BaseMutation < GraphQL::Schema::RelayClassicMutation
end
```

That's it!

Note that the module we're inheriting from is `RelayClassicMutation`--the GraphQL Ruby gem actually has another [`GraphQL::Schema::Mutation` ](https://graphql-ruby.org/mutations/mutation_classes)module, but `RelayClassicMutation` gives us some nice functionality, [especially around simplifying `input:` to accept a single hash](https://graphql-ruby.org/api-doc/1.9.12/GraphQL/Schema/RelayClassicMutation).

### Create new file for our specific mutation

In the same `/app/graphql/mutations` directory, add another file. This will be the same name as the mutation, but in snake-case: for the `createOrder` mutation, name the file `/app/graphql/mutations/create_order.rb`.

Here's what we'll add to the file to create the mutation:

```ruby
# /app/graphql/mutations/create_order.rb
class Mutations::CreateOrder < Mutations::BaseMutation
    argument :description, String, required: true
    argument :total, Float, required: true

    field :order, Types::OrderType, null: false
    field :errors, [String], null: false

    def resolve(description:, total:)
        order = Order.new(description: description, total: total, reference_key: SecureRandom.uuid)
        if order.save
            {
                order: order,
                errors: []
            }
        else
            {
                order: nil,
                errors: order.errors.full_messages
            }
        end
    end
end
```

Let's step through what we're seeing after we declare the class:

#### arguments

```ruby
# /app/graphql/mutations/create_order.rb
    argument :description, String, required: true
    argument :total, Float, required: true
```

Here, we specify the arguments that our mutation request can take. After `argument`, we supply three things:

1. name of the argument (`:description`)--we will use this as the key in our key-value pairs for inputs
2. data type (`String`)--the mutation request will throw errors if the correct data type is not provided
3. required, as a boolean (`required: true`)--this allows us to specify if an argument must be present to succeed
	* `required: true` will throw an error if not present
	* `required: false` will make the argument optional


#### fields
```ruby
# /app/graphql/mutations/create_order.rb
    field :order, Types::OrderType, null: false
    field :errors, [String], null: false
```

Here, we specify the fields that our mutation request **returns**. Our two fields, `:order` and `:errors`, will handle two cases:
* if the mutation is **successful**, an `Order` object will be returned (just like a Query)
* if the mutation **fails**, we will get back a set of errors


After `field`, we supply three things:

1. name of the field (`:order`, `:errors`)--we will use this as the key in our key-value pairs for our return data
2. data type (`Types::OrderType`, `[String]`)--these tell us what type of data to expect in the return
	* as with Queries, we can specify any data type, including our custom types created in the `/app/graphql/types/` directory
	* we can also return an array of another type, such as returning an array of errors as strings via `[String]` 
4. null, as a boolean (`required: true`)--this allows us to specify if we are allowed to receive `nil` fields in our return data
	* `null: false` will throw an error a field is `nil`
	* `null: true` will allow `nil` data to be returned without errors


#### resolve()
```ruby
# /app/graphql/mutations/create_order.rb
    def resolve(description:, total:)
        order = Order.new(description: description, total: total)
        if order.save
            {
                order: order,
                errors: []
            }
        else
            {
                order: nil,
                errors: order.errors.full_messages
            }
        end
    end
```

This is where the magic happens! All mutations have a `resolve()` function, and that function returns (as a hash) what the mutation itself will return. Let's step through the code:

* `resolve()` takes the `arguments` we specified above
* we immediately use ActiveRecord to create a new `Order`, using the data from the `arguments`
* in a familiar Rails pattern, we test if the `Order` can be saved in the database
	* if **successful**, we return a hash with the `order` key containing our newly-saved `Order` instance, and an empty array of errors
	* if **failed**, we return a `nil` `Order`, and an array of errors

This is a very straightforward `resolve()` method, but it can easily be added to! You can make and call helper functions within the `CreateOrder` class, so long as **the resolve() function ultimately returns a hash for the mutation's response**.

We're almost read to try out our first mutation! But first, we have to make sure our app knows how to route the mutation request properly.


### Add routing to `/app/graphql/types/mutation_type.rb`

By default, our `/app/graphql/types/mutation_type.rb` will be created with only a test-field that returns "Hello World", which we are directed to remove. Go ahead and delete that now, so that our class looks nice and empty:

```ruby 
# /app/graphql/types/mutation_type.rb
module Types
  class MutationType < Types::BaseObject
  end
end
```

Perfect, a blank slate!

Inside here, we now simply specify a `field` that looks for our mutation's name, and routes to the correct mutation class:

```ruby
# /app/graphql/types/mutation_type.rb
module Types
  class MutationType < Types::BaseObject
  
	field :create_order, mutation: Mutations::CreateOrder
	
  end
end
```

Now, when we send a GraphQL mutation called `createOrder`, the arguments we provide will be sent to the `Mutations::CreateOrder` class we just created in `/app/graphql/mutations/create_order.rb`!

We're *finally* ready to test!!


# Executing our first Mutation

Go ahead and run `rails s` in your terminal to start our Rails server on `http://localhost:3000/graphql/`.

Next, open up Insomnia and create a new POST request, and set it to a GraphQL structured query.

Then, add in our mutation code from above:

```graphql
mutation {
  createOrder(input: {
    description: "Octo Octa - Resonant Body (vinyl)",
    total: 21.82
  }) {
    order {
	  id
      description
      total
      payments {
        id
        amount
      }
      paymentsCount
    }
    errors
  }
}
```

Note that there are a couple differences from the Query we created last time:

* the top line says `mutation {}` instead of `query {}`--this is necessary for correct routing to `/app/graphql/types/mutation_type.rb`
* inside, we call `createOrder()` as a function, and supply `input:` as a hash containing our fields as keys
* immediately following the `createOrder()` call, we also provide a structure for the returned data, including an `order` and `errors`

Here's what we've got in Insomnia right now:

![GraphQL mutation in Insomnia](https://thepracticaldev.s3.amazonaws.com/i/1hu3klrpy00cyp0zzxkd.png)

Go ahead and send the request, and you'll see it comes back **successful**. We can access our newly created (and saved!) `Order` via the `order` key. We can also see that our array of errors is empty:

![GraphQL mutation in Insomnia, also showing request's return data](https://thepracticaldev.s3.amazonaws.com/i/4y9knmd0c95bg4wzkoby.png)


Now, let's test a **failed** mutation. Remove the `description:` field of the input entirely:

```graphql
mutation {
  createOrder(input: {
    total: 21.82
  }) {
    order {
	  id
      description
      total
      payments {
        id
        amount
      }
      paymentsCount
    }
    errors
  }
}
```

And resend the request, and you'll see it comes back with an error describing a missing required input field named "description":

![GraphQL mutation in Insomnia, showing errors from missing input field](https://thepracticaldev.s3.amazonaws.com/i/lmtj6zatu0ytos9lhbbb.png)

Great! The errors provided by the GraphQL Ruby gem are *very* explicit, so make sure to read them closely when debugging.

# Conclusion

We've now implemented a GraphQL API with the ability to read `Orders` from our database, and now create new `Orders` too! From here, we can build new mutations to handle updating and deleting data as well.

[Here's the repo for the code in this article, too. Feel free to tinker around with it!](https://github.com/isalevine/devto-graphql-ruby-api)

And once again -- __*thank you*__ to Matt Boldt and [his AWESOME Rails GraphQL tutorial](https://mattboldt.com/2019/01/07/rails-and-graphql/) for helping me get this far! <3

Any tips or advice for using GraphQL in Rails, or GraphQL in general? Feel free to contribute below!