How to Use GraphQL with Ruby on Rails
Tags: ruby, tutorial, graphql, rails
Published: 2019-11-15 15:57:30

---
title: How to Use GraphQL with Ruby on Rails
published: true
date: 2019-11-13 19:37:08 UTC
tags: ruby, tutorial, graphql, rails
canonical_url: https://web-crunch.com/how-to-use-graphql-with-ruby-on-rails/
---

[GraphQL](https://graphql.org/) is a query language for APIs. The query language itself is universal and not tied to any frontend or backend technology. This characteristic makes it a great choice for many frameworks or patterns you or your company might follow.

Today, I’m going to build a basic API using GraphQL. This will only cover backend/api concepts. In the future I plan to add an additional tutorial on implementing a front-end around the same concepts. Look for that soon!


{% youtube kSlJH3hrV58 %}

[Download the source code](https://github.com/justalever/graphql_fun)

{% github  https://github.com/justalever/graphql_fun %}
### Create the app

For this app we will leverage the API mode Rails has baked in. This essentially eliminates the view layer and allows you to opt in to middleware as you see fit. [Read more about the API mode here](https://guides.rubyonrails.org/api_app.html).

```bash
$ rails new graphql_fun --api --skip-test

```

[GraphQL](https://graphql.org/) comes with some concepts that you need to understand to use it effectively. Here are those concepts and their definitions.

- **Queries** – Fetch specific data from the API. Typically these are read-only like `GET` requests.
- **Mutations** – Some type of modification of data on the API. e.g. `CREATE, UPDATE, DESTROY`.
- **Types** – Used to define datatypes, or in our case, Rails models. A type contains fields and functions that respond with data based on what is requested. Types can also be static, like `String` or `ID` which come from the server side library.
- **Fields** – Represent the attributes for a given type (like attributes on a model).
- **Functions** – Supply the above fields with data (like methods on a model). 

### Create the models

We’ll use a basic blog concept without any form of authentication layer to keep things simple.

```bash
rails g model User email:string name: string
rails g model Post user:belongs_to title:string body:text
rails db:migrate

```

Update your `user.rb` model to have the following relation:

```ruby
# app/models/user.rb
class User < ApplicationRecord
  has_many :posts
end

```

### Installing Gem dependencies

Since we need GraphQL itself, that means we need to install the ruby port of GraphQL as a gem. On top of the main ruby implementation of the language we’ll use a nice development utility that allows us to perform queries in the browser called GraphiQL.

I’ll also be using the popular gem called `faker` to save time seeding some data for us to use.

```ruby
# Gemfile

gem 'graphql'

group :development do
  gem 'graphiql-rails'
  gem 'faker'
end

```

Be sure to run `bundle install` after adding these to your Gemfile.

### Seeding data

Below I’ve added some dummy data in `db/seeds.rb`. You can user the `Faker` gem we added to generate filler content on the fly.

```ruby
# db/seeds.rb

5.times do
  user = User.create(name: Faker::Name.name, email: Faker::Internet.email)
  5.times do
    user.posts.create(title: Faker::Lorem.sentence(word_count: 3), body: Faker::Lorem::paragraph(sentence_count: 3))
  end
end

```

We create 5 users with 5 posts for each user by running:

```bash
$ rails db:seed

```

### Adding GraphQL files

In order to work with GraphQL we need to use different files not typically associated with a rails application. Thanks to the graphql gem we have access to new generators. You can see what generators are in your arsenal by running `rails generate` inside your application folder on the command line.

A new section should appear that looks similar to the following:

```bash
Graphql:
  graphql:enum
  graphql:install
  graphql:interface
  graphql:loader
  graphql:mutation
  graphql:object
  graphql:scalar
  graphql:union

```

We can generate the necessary files we need by running the following.

```bash
# install graphql
$ rails generate graphql:install
$ bundle install

# generate objects (similar to our typical rails model layer)
$ rails generate graphql:object user
$ rails generate graphql:object post

```

Running the install generator creates quite a few files as well as adds a new route:

```bash
$ rails generate graphql:install
Running via Spring preloader in process 30494
      create app/graphql/types
      create app/graphql/types/.keep
      create app/graphql/graphql_fun_schema.rb
      create app/graphql/types/base_object.rb
      create app/graphql/types/base_argument.rb
      create app/graphql/types/base_field.rb
      create app/graphql/types/base_enum.rb
      create app/graphql/types/base_input_object.rb
      create app/graphql/types/base_interface.rb
      create app/graphql/types/base_scalar.rb
      create app/graphql/types/base_union.rb
      create app/graphql/types/query_type.rb
add_root_type query
      create app/graphql/mutations
      create app/graphql/mutations/.keep
      create app/graphql/types/mutation_type.rb
add_root_type mutation
      create app/controllers/graphql_controller.rb
       route post "/graphql", to: "graphql#execute"
Skipped graphiql, as this rails project is API only
  You may wish to use GraphiQL.app for development: https://github.com/skevy/graphiql-app

```

Our routes.rb file is as simple as the following:

```ruby
# config/routes.rb
Rails.application.routes.draw do
  post "/graphql", to: "graphql#execute"
end

```

And our `User` and `Post` object are new files that get created inside a new folder to the app called `graphql/types`.

The current structure looks like the following:

```bash
graphql
├── graphql_fun_schema.rb
├── mutations
└── types
    ├── base_argument.rb
    ├── base_enum.rb
    ├── base_field.rb
    ├── base_input_object.rb
    ├── base_interface.rb
    ├── base_object.rb
    ├── base_scalar.rb
    ├── base_union.rb
    ├── mutation_type.rb
    ├── post_type.rb
    ├── query_type.rb
    └── user_type.rb

```

### Visualizing queries

If you recall a bit before we added a second gem to our development environment that lets you perform and visualize GraphQL queries on the fly. We need to extend our `routes.rb` file to only load this in the development environment of the app. That would look like the following:

```ruby
# config/routes.rb

Rails.application.routes.draw do
  if Rails.env.development?
    mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "graphql#execute"
  end
  post "/graphql", to: "graphql#execute"
end

```

Think of GraphiQL as a GUI for GraphQL. GraphQL only has a single endpoint unlike more conventional RESTful routing which generates quite a few absolute paths for different request types.

Now, visiting localhost:3000/graphiql on your local rails server will give you a nice UI to use.

#### Small gotcha

Because we are in API mode there’s no concept of an asset pipeline in play. That framework has been commented out by default in `config/application.rb` If you tried to boot your server right now it would boot but visiting the GraphiQL path would result in an error. To fix this we need to un-comment a line in `application.rb` and restart your server.

```ruby
# config/application.rb

require_relative 'boot'

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
require "sprockets/railtie" # <- uncomment this line!
# require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module GraphqlFun
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    # Only loads a smaller set of middleware suitable for API only apps.
    # Middleware like session, flash, cookies can be added back manually.
    # Skip views, helpers and assets when generating a new resource.
    config.api_only = true
  end
end

```

On top of this issue we need to provide a manifest.js file within `app/assets/config/manifest.js`. You’ll need to create those files and folders for this to work.

```bash
assets
└── config
    └── manifest.js

```

Inside the manifest file add the following:

```javascript
//= link graphiql/rails/application.css
//= link graphiql/rails/application.js

```

Boot your server once more and you should hopefully be back in action.

### GraphQL Types

For the `User` and `Post` models we need to create types so that GraphQL knows what kind of data to send back. Here I can specify what columns, methods, and more that will return to the app.

Starting with the `UserType` let’s ammend the `user_type.rb` file to include the following.

```ruby
# app/graphql/types/user_type.rb
module Types
  class UserType < Types::BaseObject
    field :id, ID, null: false
    field :name, String, null: true
    field :email, String, null: true
    field :posts, [Types::PostType], null: true
    field :posts_count, Integer, null: true

    def posts_count
      object.posts.size
    end
  end
end

```

Each field gets an object “type” and a null option of whether or not it needs to be present for the query to be consider successful. Passing types and null booleans tells GraphQL what to expect so it knows how to parse data on both the backend and client side parts of the app.

I added a method called `posts_count` that simply grabs the amount of posts in the database. This doesn’t exist on the model directly so we invented it. In these type of methods we get the word `object` for free. It refers to the Rails model in mention. In this case, `User`.

You may notice `id` and `name` don’t have functions tied to them. These are already mapped thanks to the models we generated with Rails before hand.

The `PostType` file is a bit simpler.

```ruby
# app/graphql/types/post_type.rb

module Types
  class PostType < Types::BaseObject
    field :id, Integer, null: false
    field :title, String, null: false
    field :body, String, null: false
  end
end

```

## The Main Query Type

With GraphQL there are two types of requests that get routed to `query_type.rb` and `mutation_type.rb`. These have already been referenced when we ran the install generator. That file is called `your_appname_schema.rb`. You can think of this file like a routing type of file. Mine looks like the following:

```ruby
# app/graphql/graphql_fun_schema.rb
class GraphqlFunSchema < GraphQL::Schema
  mutation(Types::MutationType)
  query(Types::QueryType)
end

```

We need to amend `app/graphql/types/query_type.rb` to accomodate for our new `UserType`. Doing so looks like the following:

```ruby
# app/graphql/types/query_type.rb 
module Types
  class QueryType < Types::BaseObject
    # /users
    field :users, [Types::UserType], null: false

    def users
      User.all
    end

    # /user/:id
    field :user, Types::UserType, null: false do
      argument :id, ID, required: true
    end

    def user(id:)
      User.find(id)
    end
  end
end

```

Here I’m defining what `users` and `user` bring back for us. We need to define these fields and their appropriate ruby methods for determining the response. The `users` field returns an array of UserType objects (multiple users) and can never be empty (nil). The `user` field accepts an `id` argument and returns a single user. It to, can never be nil.

We can test out our work in at `localhost:3000/graphiql`. A GraphQL query for users looks like the following:

```bash
query {
  users {
    name
    email
    postsCount
  }
}

```

If all goes swimmingly you should see a response back of all the users.

And if querying a specific user you should return only one:

```bash
query {
  user(id: 2) {
    name
    email
    posts {
      title
    }
  }
}

```

Based on the relationship between our data we can nest posts within the user query and return all the posts of the given user whose ID equals 2.

## Mutations

Mutating data is exactly how it sounds. In the RESTful world this is your UPDATE, PUT, POST, DELETE responses.

We can setup a base class and extend it for each future mutation we create. Create a new file in `app/graphql/mutations/` called `base_mutation.rb`

Inside that file add the following.

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

```

Consider this a shell of all our future mutations.

Some terminology is in order when it comes to understanding mutations

- **Arguments** – arguments to accept as params, which are required, and what object types they are. This is similar to defining strong params in a Rails controller, but with more fine grained control of what’s coming in.
- **Fields** – Same concept as our Query fields from before. In my case, I accepted arguments to create a new user. I want to return a `user` field with our new model accompanied with an array of `errors` if any exist.
- **Resolver** – The `resolve` method is where we execute our ActiveRecord commands. It returns a hash with keys that match the above field names. 

Putting those to work looks like this:

```ruby
# app/graphql/mutations/create_user.rb

class Mutations::CreateUser < Mutations::BaseMutation
  argument :name, String, required: true
  argument :email, String, required: true

  field :user, Types::UserType, null: false
  field :errors, [String], null: false 

  def resolve(name:, email:)
    user = User.new(name: name, email: email)
        if user.save
      {
        user: user,
        errors: []
      }
    else
      {
        user: nil,
        errors: user.errors.full_messages
      }
    end
  end
end

```

A few notes:

- Notice how we are inheriting the base\_mutation class.
- Much like a controller we check if a user saved and return a response. The same is true if there are errors during creation.

### Adding the CreateUser mutation type

With our mutation response work out of the way we can add the new mutation to the mutation type class so it’s exposed to our API

```ruby
# app/graphql/types/mutation_type.rb

module Types
  class MutationType < Types::BaseObject
    field :create_user, mutation: Mutations::CreateUser
  end
end

```

### Creating a user

Now we can build a query to create a user and return the same user and/or errors if present.

```bash
mutation {
 createUser(input: {
   name: "Andy Leverenz",
   email: "andy@web-crunch.com"
 }) {
   user {
     id,
     name,
     email
   }
   errors
 }
}

```

In my logs I can see that a user was indeed created:

```bash
Started POST "/graphql" for ::1 at 2019-11-03 15:22:20 -0600
Processing by GraphqlController#execute as */*
  Parameters: {"query"=>"mutation {\n createUser(input: {name: \"Andy Leverenz\", email: \"andy@web-crunch.com\"}) {\n user {\n id\n name\n email\n }\n errors\n }\n}\n", "variables"=>nil, "graphql"=>{"query"=>"mutation {\n createUser(input: {name: \"Andy Leverenz\", email: \"andy@web-crunch.com\"}) {\n user {\n id\n name\n email\n }\n errors\n }\n}\n", "variables"=>nil}}
   (0.0ms) begin transaction
  SQL (0.7ms) INSERT INTO "users" ("email", "name", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["email", "andy@web-crunch.com"], ["name", "Andy Leverenz"], ["created_at", "2019-11-03 21:22:20.095509"], ["updated_at", "2019-11-03 21:22:20.095509"]]
   (0.6ms) commit transaction
Completed 200 OK in 16ms (Views: 0.1ms | ActiveRecord: 1.7ms)

```

Pretty slick stuff!

### Part 2 featuring the front-end coming soon!

For now we have our GraphQL/Rails set up working great. We didn’t need extra routes, controllers, or serializers to achieve the same work done here. What’s great is that we are only returning the data way ask for and type-checking at the same time. GraphQL is very powerful and I’m beginning to see what all the fuss is about.

Look forward to a front-end follow up to this tutorial coming soon. We’ll use similar queries to construct a view layer with a front-end framework (mostly likely React + Apollo). Until then, thanks for following along!

#### Shameless plug time

[![](https://i1.wp.com/web-crunch.com/wp-content/uploads/2019/01/YouTube-Promo3.jpg?resize=3840%2C2160&ssl=1)](http://hellorails.io)

I have a new course called [Hello Rails](https://hellorails.io). Hello Rails is a modern course designed to help you start using and understanding Ruby on Rails fast. If you’re a novice when it comes to Ruby or Ruby on Rails I invite you to check out the site. The course will be much like these builds but a super more in-depth version with more realistic goals and deliverables. [Download your copy today!](https://hellorails.io/)!

Follow [@hello\_rails](https://twitter.com/hello_rails) and [myself @justalever](https://twitter.com/justalever) on Twitter.

The post [How to Use GraphQL with Ruby on Rails](https://web-crunch.com/how-to-use-graphql-with-ruby-on-rails/) appeared first on [Web-Crunch](https://web-crunch.com).