GraphQL is exciting.

Why? It’s an innovative way of managing the relationship between client and server, in a way that makes building both sides easier and faster.

Some hail it as the end of REST. Instead of calling individual endpoints to get data—each endpoint tailored to distributing a specific piece of the data— we call a single endpoint and get back all the information we want, structured exactly the way we want it.

In this tutorial, we’ll build a simple Rails and GraphQL API. By the end, you’ll know how to integrate GraphQL into an existing Rails application, and also get glimpse of why the protocol is so exciting.

Let’s get to it.

What We’re Going to Build

GraphQL is all about relationships—picturing your database as literally a graph of related nodes. To match that, let’s create a simple relationship schema.

In fact, we’ll use the best relationship of all: between people and their pets.

Say you have a database with Person models and Pet models. You’re working on the front-end of an application to display each person in the database, along with their pets. But you also want to display the reverse—to show all the pets along with their people.

In the old REST paradigm, you’d need two endpoints to achieve this. We’re going to do it in one.

Here is the JSON data we want to eventually receive.

Call 1, to get people with their pets:

{

data: {

people: [

{

name: 'Scott',

surname: 'Domes',

pets: [{ name: 'Colby' }, { name: 'Jessie' }]

}

]

}

}

Call 2, to get the pets each with their person:

{

data: {

pets: [

{

name: 'Colby',

person: {

name: 'Scott'

}

},

{

name: 'Jessie',

person: {

name: 'Scott'

}

}

]

}

}

We’re going to build our Rails app, and then do the GraphQL good stuff.

Setting Up Rails

Open up a terminal in a working directory and run the following commands:

rails new people --api

cd people/

rails generate model Person name:string surname:string

rails generate model Pet name:string person:references type:string

rake db:migrate

In the above, we create our app (as an API), then create models for people and pets.

If you open up app/models/pet.rb , you’ll see the model already belongs to a person.

Open up app/models/person.rb and we can add the other side of the relationship:

class Person < ApplicationRecord

has_many :pets

end

Now we have a relationship between people and pets. Pets belong to people, who have multiple pets.

Before we move to the GraphQL bit, let’s populate our database.

Open up the Rails console with rails c and then run the following commands (with your name, of course):

scott = Person.create(name: 'Scott', surname: 'Domes')

scott.pets.create(name: 'Colby')

scott.pets.create(name: 'Jessie')

Installing GraphQL

It’s so easy: in your Gemfile add gem 'graphql' and then run bundle install . (Make sure to exit your Rails console first!)

Then, inside app/ , create a types folder. This is where all our GraphQL logic will live.

Schemas & Types

Now we can talk GraphQL.

GraphQL relies on two concepts: schemas and types.

Schemas define what data is available, and what type it is. Types determine the structure of the data (what it looks like).

1 is of the integer type. “Hello” is of the string type. Our Person model will be an object type — a type that has fields. What fields those are depends on how we define our PersonType.

All of the above is pretty abstract, so let’s see what it looks like by creating a PersonType.

Our First Type

Inside types/ create a new file, called person_type.rb , and type the following:

PersonType = GraphQL::ObjectType.define do

name "Person"

description "A Person"

field :id, types.ID

field :name, types.String

field :surname, types.String

field :pets do

type types[PetType]

resolve -> (person, args, ctx) {

person.pets

}

end

end

We define our PersonType with a name, a description, and then a list of fields. A field is define by a symbol indicating its name, and then what type that field is.

All looks rather straightforward until we get to the field :pets. Here, we see a pet is of the PetType (which we’ll create in a moment). But in order to tell GraphQL where to get the data for the pet, we have to add a resolve function, which grabs the person’s pets.

What resolve does is get the data from person.pets, and then runs that data through the PetType to structure it.

Speaking of which…

Our Second Type

# types/pet_type.rb PetType = GraphQL::ObjectType.define do

name "Pet"

description "A Pet"

field :id, types.ID

field :name, types.String

field :person do

type PersonType

resolve -> (pet, args, ctx) {

pet.person

}

end

end

There’s the other half of the equation.

Here, the :person field will grab the pet.person, and then structure it according to the PersonType. This means we can then access the person’s name, surname, and pet, if we want.

Our Schema and QueryType

Now that we have our Types defined, we need a way to query the data we want.

We need a way to tell our API, “hey, give me all the people and their pets” and “hey, give me all the pets with their owners”.

To do that, we need to do three things:

Define our QueryType (how our query is going to appear). Define our Schema Make a route to send the queries to.

After that, we’ll be ready to start testing our API!

Our QueryType

The QueryType is the gateway to our data. It defines how requests can ask for data.

Create a new file in the types/ folder called query_type.rb and define it as so:

QueryType = GraphQL::ObjectType.define do

name "Query"

description "The query root for this schema" field :pets do

type types[PetType]

resolve -> (obj, args, ctx) {

Pet.all

}

end field :people do

type types[PersonType]

resolve -> (obj, args, ctx) {

Person.all

}

end

end

We open up two fields to our query, :pets and :people. Those fields will then grab the data from Person.all or Pet.all , and filter it through the PersonType and PetType , respectively.

What does this mean? It means we can structure our query like so:

query {

people {

name

surname

pets {

name

}

}

}

And the GraphQL will process it in the following steps:

QueryType → :people field → PersonType → :name, :surname, :pets fields → PetType → :name field

It will then organize the data exactly as we have defined it above.

Before we see that in action, though, we have to do a little more housekeeping.

Defining Our Schema

Create a new file in the types/ folder called schema.rb , like so:

Schema = GraphQL::Schema.define do

query QueryType

end

Our Schema is defined so that we can make a query against it. Not much exciting here.

Defining Our Query Route

Lastly, we need a way into our API: a query route.

The beauty of GraphQL is that all requests for data go through a single endpoint.

Let’s create that endpoint now. Inside config/routes.rb , add the following line before the end .

post '/query' => 'application#query'

When we send a POST request to ‘http://localhost:3001/query’, it’ll call the #query method inside our ApplicationController. Next, we’ll create that method.

# app/controller/application_controller

class ApplicationController < ActionController::API

def query

result = Schema.execute(

params[:query]

)

render json: result

end

end

(Make sure to delete the protect_from_forgery line if it exists)

When this endpoint is called, we execute it according to our GraphQL Schema, based on the query defined in the request params. Then, we send the response back as JSON.

Okay, let’s see it in action!

Testing Our Query

Install and open Postman, and start up our app with rails server -p 3001 .

At the start of this tutorial, we defined two queries as our goal. One was to fetch all the people with their pets, and the second was to fetch all the pets with their people.

Here’s what the two look like in Postman, as the body of our POST request.

Query 1:

{

"query":

"{

pets {

name

person {

name

}

}

}"

}

Query 2:

{

"query":

"{

people {

name

surname

pets {

name

}

}

}"

}

In Postman: