Basics of GraphQL in Ruby
Introduction — What is GraphQL?
GraphQL is an open-source data query language and server-side runtime for APIs.
It is available for multiple languages. Query and mutation results are returned in JSON format.
In this article, I will show how to easily implement it and use it in an ROR API application.
Why GraphQL and not a REST API?
It’s more flexible, easier for developers to integrate, and a huge advantage is that it allows you to pull the exact data you want from multiple data sources in a single API call from a single endpoint.
We will use graphiql-app to test our API.
Let’s start developing GraphQL API in a RoR project.
First, add the `graphql` gem to your Gemfile.
#Gemfile
gem "graphql"
The next required step is to run the generator.
rails g graphql:install
It creates a new directory under app/graphql with a group of files, for now the important ones for us are queries that are used to read data available in app/graphql/types/query_type.rb
and mutations that are used to write data and are defined as separate files under app/graphql/types/mutation_types
.
Queries
Let’s assume that our application has a post model with title and body attributes.
In order to query for records, we need to define a post type with a list of all available attributes as below:
# app/graphql/types/post_type.rb
class Types::PostType < Types::BaseObject
description “Single Blog Post”
field :id, ID, null: false, description: “Identifier of Post”
field :title, String, null: false, description: “Title of Post”
field :body, String, null: false, description: “Body of Post”
field :created_at, GraphQL::Types::SO8601DateTime, null: false, description: “Datetime of Post creation”
field :updated_at, GraphQL::Types::SO8601DateTime, null: false, description: “Datetime of Post last update”
end
Next, we need to define a query method for a single post and a collection of posts:
# app/graphql/types/query_type.rb
field :post, Types::PostType, null: true, description: "Returns one Post instance" do
argument :id, ID, required: true
end
def post(id:)
Post.find_by(id: id)
end
field :posts, [Types::PostType], null: true, description: "Returns collection of Posts"
def posts
Post.all
end
Now we should be able to query the data on the GraphQL client with one of the following examples:
{
post(id: "12d08a32-1cee-4681-84d0-4ef45a51203b") {
id
title
body
}
}
{
posts {
Id
Title
Body
}
}
As you may have noticed all attributes that are returned in the response are camelcased, if you want to keep the snakecase format you need to add camelize: false in the argument definition.
Mutations
As we already know mutations are used to create/update/delete data, so now it’s time to define all these 3 methods for our post model in GraphQL as separate mutation files.
For create Post
# app/graphql/mutations/create_post.rb
class Mutations::CreatePost < GraphQL::Schema::Mutation
field :create_post, Types::PostType, null: true, description: "Create an Post" do
argument :title, String, required: true
argument :body, String, required: true
end
def resolve(title:, body:)
Post.create(title: title, body: body)
end
end
For update Post
# app/graphql/mutations/update_post.rb
class Mutations::UpdatePost < GraphQL::Schema::Mutation
field :update_post, Types::PostType, null: true, description: "Create an Post" do
argument :id, ID, required: true
argument :title, String, required: true
argument :body, String, required: true
end
def resolve(id:, title:, body:)
post = Post.find(id)
post.update(title: title, body: body)
end
end
For delete Post
# app/graphql/mutations/delete_post.rb
class Mutations::DeletePost < GraphQL::Schema::Mutation
field :create_post, Types::PostType, null: true, description: "Create an Post" do
argument :id, ID, required: true
end
def resolve(title:, body:)
Post.find(id).destroy
end
end
In the last step, we need to update the list of available mutations.
# app/graphql/types/mutation_type.rb
field :create_post, Types::PostType, mutation: Mutations::CreatePost
field :update_post, Types::PostType, mutation: Mutations::UpdateaPost
field :update_post, Types::PostType, mutation: Mutations::DeletePost
Now our API is ready to process all these 3 operations, let’s try them out on the examples below:
mutation {
createPost(title: "New Post", body: "Another fantastic Post") {
id
title
body
}
}
mutation {
updatePost(id: "12d08a32-1cee-4681-84d0-4ef45a51203b", title: "Updated Post", body: "Updated Body") {
id
title
body
}
}
mutation {
deletePost(id: "12d08a32-1cee-4681-84d0-4ef45a51203b") {
id
}
}
You can find more examples and code for a sample application at: https://github.com/mosinski/graphql-api.
Words by Miłosz Osiński, Product & Platform Engineer
Editing by Kinga Kuśnierz, Content Writer