Building an API with GraphQL and Rails
Image from [fiver]
As you all know, Rails is very popular for creating a web application in a short amount of time. Today, developers tend to separate concerns in their application by creating an API for the backend and consume it with any library of their choice.
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
Table of contents
# Prerequisites
# Project Setup
# Models
# Queries
# Mutations
# Conclusion
# Prerequisites
Before we begin, make sure you have ruby version ≥ 2.2 and rails version ≥ 5 installed on your local machine.
If your ruby version is not up-to-date, you can update with a ruby version manager such as rvm or rbenv
$ rvm install "ruby-2.4.6"
or
$ rbenv install 2.4.6## You can update rails by running
$ gem update rails
That's all you need, you are good to start this awesome journey of building a simple GraphQL API with Rails.
# Project Setup
For this tutorial, you are expected to have the following tools:
- Postgres Database
- An Editor
Let's run rails in the command line to create all the files and folders we need for a basic Rails application using Postgres database.
$ rails new todo-app --database=postgresql
$ cd todo-app
To create a graphql application with rails, we will need to add a gem called graphql. Add this gem to your Gemfile.
# Gemfile
gem 'graphql'
Install the gem by running:
$ bundle install
Hurray, the gem is now installed successfully. To create all files and folders needed for a GraphQL API, run:
$ rails generate graphql:install
Running this will add graphiql-rail gem to your Gemfile. This gem will allow us to interact with the API.
To connect our application to the Postgres database, go to config/database.yml file and add your Postgres username and password to both test environment and development environment.
development:
<<: *default
database: todo_app_development
username: YOUR_POSTGRES_USERNAME
password: YOUR_POSTGRES_PASSWORDtest:
<<: *default
database: todo_app_development
username: YOUR_POSTGRES_USERNAME
password: YOUR_POSTGRES_PASSWORD
Create the database by running:
$ rails db:create
Finally, run the server by running:
$ rails server
Visit this route localhost:3000/graphiql and you should see a graphql client which can be used to place a request to our graphql server.
Graphiql
For this todo application, we will create a todos table that has two fields: title and description. Create the model by running:
$ rails generate model Todo title:string description:text
You can validate the title and the description field by making sure it is always specified before entering the database. Navigate to models/todos.rb and add rails validation.
class Todo < ApplicationRecord
validates :title, presence: true
validates :description, presence: true
end
Run migration by running:
$ rails db:migrate
Let’s add some data into our database by running rails console using:
$ rails console
>- Todo.create(title: 'Sample title', description: 'Sample Description')
Rails console
GraphQL schema has three special root types, these are called Query, Mutation and Subscription
- Queries: are GraphQL features that enable data fetching from the database. It works like a GET call in Rest APIs.
- Mutations: are GraphQL features that allow a client sends data to the database. It works like POST, PUT and DELETE in REST API’s.
- Subscriptions: Subscriptions are a GraphQL feature that allows a server to send data to its clients when a specific event happens. Subscriptions are usually implemented with WebSockets. [Action Cable]
Let's create our first query to get all todos from the database.
Create a new type for todos by creating a new file: app/graphql/types/todo_type.rb.
#app/graphql/types/todo_type.rbmodule Types
class TodoType < Types::BaseObject
field :title, String, null: false
field :description, String, null: false
end
end
It inherits from BaseObject, checkout out app/graphql/types/base_object.rb. It inherits from Graphql schema type instead of writing GraphQL::Schema::Object, just inheriting from BaseObject gives us all attributes needed to create an object Schema.
The next step is to create a query type that will be used to get all todos. Go to app/graphql/types/query_type.rb. Add a new field to the query type. :all_todos to get all our todos.
# app/graphql/types/query_typefield :all_todos, [TodoType], null: false,
description: "Returns all todos"
def all_todos
Todo.all
end
The [TodoType] is added because we are expecting a list of todos.
Over to the browser and write a query like this:
query {
allTodos {
title
description
}
}
With this, it will return all the todos in the database, we can choose to skip the title and ask for the description and vice-versa.
The next step is to add a mutation to create todos. Before that, let’s create a BaseMutationclass that inherits from GraphQL::Schema::Mutation. This will enable us to inherit from BaseMutation going forward.
Create a new file called base_mutation.rb in apps/graphql/mutations folder. Add this code:
module Mutations
class BaseMutation < GraphQL::Schema::Mutation
null false
end
end
Fine, that is out of the way. Let’s create a mutation to add todo. To do this we will create a file called add_todo.rb in the mutations folder and add this code.
#app/graphql/mutations/add_todo.rb
module Mutations
class AddTodo < BaseMutation
argument :title, String, required: true
argument :description, String, required: true
type Types::TodoType
def resolve(title: nil, description: nil)
Todo.create!(title: title, description: description)
rescue ActiveRecord::RecordInvalid => e
GraphQL::ExecutionError.new(e.record.errors.full_messages.
join(','))
end
end
end
This code add AddTodo mutation specifying the argument needed and the type that will be returned.
There is a rescue block in the mutation code. GraphQL in rails has an error handling block which is GraphQL::Execution.new(error_messages).
Add the created mutation to mutation type so it will be accessible to the client.
# app/graphql/types/mutation_type.rb
module Types
class MutationType < Types::BaseObject
field :add_todo, mutation: Mutations::AddTodo
end
end
Test it on your browser by creating some todos using this query.
mutation {
addTodo(title: "New Todo", description: "I will eat rice") {
title
description
}
}
Hurray!!!!!, we have created some todos and also know how to get todos from our database through the use of queries. I will be writing another article for performing authorization and authentication to ensure a user can log in, delete and also update their todos.
With this article, I believe you can create a simple API with Rails and GraphQL.
This was very useful! Thank you!