Wolfpack Digital web development team uses Ruby on Rails and tries new ways of coding like using GraphQL and Nuxt.js

GraphQL with Ruby on Rails and Nuxt.js— Part 1

Besides playing by the rules, we create our own rules in building digital products. At Wolfpack Digital, we use proven methods to build flawless web apps in Ruby on Rails. Still, we want to keep the innovation going. This is how, at one of our Web Howl Group meetings, we decided to experiment with GraphQL.

Florin Ionce
Wolfpack Digital

--

In this step-by-step tech article, we are going to cover the following topics:

  • What is GraphQL;
  • How to use GrahpQL in a Rails application;
  • How to write GraphQL Queries and Mutations using Rails;
  • What graphiql has to offer, in practice.

What Is GraphQL?

GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. GraphQL isn’t tied to any specific database or storage engine and is backed by your existing code and data instead.

Basically, GraphQL is a modern way of building and querying APIs. But the cool thing is that, unlike REST APIs, it lets the client determine what data to return. Pretty cool, right?

GraphQL comes with some specific features, and I’m going to present them briefly before starting with our example.

  • Query — It’s used to fetch data from the database. It’s similar to the GET requests from a REST API.
  • Mutation — It’s used to insert, modify or delete data in the database.
  • Type — It’s used to define the datatypes of the objects. Think of them as the models we have in rails. They can contain fields and functions, just like a model.

Setup the Rails Application

Enough with the introduction, let’s generate a Rails application. It will be a simple API for blog posts.

Let’s start by running the following command:

rails new blogposts_graphql_api — skip-test — api

Of course, this is just an example so I’ll skip the tests, but don’t do that on a real application.

The next step is to create two models: User which contains email and name (I know what you are going to say, but this is just a demo) and a blogpost which has a user_id, title, and body.

bin/rails g model User email:string name:string
bin/rails g model Blogpost user:belongs_to title:string body:text

Don’t forget to create and migrate the database.

bin/rails db:create
bin/rails db:migrate

Open the app/models/blogpost.rb file and add the following line:

belongs_to :user

Similarly, add has_maby :blogposts inside the app/models/user.db file. This is just to define the relations between the models inside the Rails application.

▶ See the commit here.

Add GraphQL Dependencies

The next thing I’m going to do is install the graphql-ruby gem by adding it in the Gemfile. I’ll also add the graphiql-rails gem in the development group only, which is used to visually test the API, check the documentation. But we’ll see how to use it later.

gem 'graphql', '~> 1.9', '>= 1.9.4'group :deveopment do
gem 'graphiql-rails', '~> 1.7'
....
end

We need to run bundle install to install the new dependencies and then generate the files and folders needed by GraphQL by running bin/rails g graphql:install

NOTE: you may need to run thebundle install command again in order to also install graphiqlgem.

We can now generate the Userand Blogpost GraphQL objects by running:

rails generate graphql:object user
rails generate graphql:object blogpost

We’ll also add the /graphql and /graphiql routes in the config/routes.rb file.

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

▶ You can see all the changes from this section in this commit.

Add Faker and Some Random Data

NOTE: This step is optional

Before we start playing with GraphQL we should make sure we have some data in our database first. In order to do that, I’ll add the faker gem.

I simply added gem ‘faker’, git: ‘https://github.com/stympy/faker.git', branch: ‘master’ in the Gemfile and ran bundle install.

After we have the gem installed we can add the following in the db/seeds.rb file

5.times do
user = User.create(
email: Faker::Internet.unique.email,
name: Faker::Movies::StarWars.unique.character
)
3.times do
Blogpost.create(
user: user,
title: Faker::Movies::StarWars.quote,
body: Faker::Lorem.paragraphs(rand(2..8)).join('.')
)
end
end

After we run bin/rails db:seed we’ll have 5 users, each having 3 blog posts in our database.

▶ See the commit here.

Create Our First Queries and Mutations

Now that we have everything set up, we can start building our first queries and mutations.

Queries

We’ll start by opening the app/graphql/types/user_type.rb file and add the following:

module Types
class UserType < Types::BaseObject
field :id, ID, null: false
field :name, String, null: true
field :email, String, null: true
field :blogposts, [Types::BlogpostType], null: true
field :blogposts_count, Integer, null: true
def blogposts_count
object.blogposts.count
end
end
end

This is not that different than an Active Model Serializer file, we can see that we are mapping the database fields, setting their types and we also have a function called blogposts_count. This is just to see how to use a function, I know using thatcounter_cache would be better.

Also, we notice that the field blogposts is returning an array of Types:BlogpostType which was not defined yet. So, let’s go ahead and open the app/graphql/types/blogpost_type.rb file and add the following:

module Types
class BlogpostType < Types::BaseObject
field :id, ID, null: false
field :title, String, null: true
field :body, String, null: true
field :body_short, String, null: true
field :user_id, ID, null: false
def body_short
object.body&.truncate(20)
end
end
end

Now that we have these two types defined, we need to register them in the base query type. I order to do that, we simply open app/graphql/types/query_type.rb and do the following:

  • Register the users field.
  • Define the users method which queries all the users
  • Register the user field — similar to the show method
  • Define the user method — responsible for fetching a user from the database.
module Types
class QueryType < Types::BaseObject
field :users, [Types::UserType], null: false
field :user, Types::UserType, null: false do
argument :id, ID, required: true
end
def users
User.all
end
def user(id:)
User.find(id)
end
end
end

It’s finally the time to open the rails application and start testing the application.

Run bin/rails server and go to http://localhost:3000/graphiql

We’ll see the graphiql interface and we can start writing queries in the left side. We’ll start with a simple query which returns all the users and the blogposts for each user. This is where the hierarchical design of GraphQL is an advantage because we can see how easily we can get all the blog posts for a user from the database.

query {
users {
name
id
blogpostsCount
blogposts {
id
title
bodyShort
body
}
}
}
Our first GraphQL query

You can see how easy it is to define queries and chose what we get on the client. If we didn’t need the blog posts, we would just remove them from the query.

Let’s see how we send an argument to a query:

query {
user(id: 6) {
name
id
blogposts {
title
bodyShort
user {
id
}
}
}
}

We simply pass the (id: ..) on the query and voila — we get only one user.

PS: Did you see the docs button on the top right corner? GraphiQL provides documentation for all our queries and mutations. How cool is that?

▶ You can check the commit for this part here.

Mutations

Now that we know how to query data, let’s see how to make mutations.

For convenience, I’ll create a BaseMutation class — app/graphql/mutations/base_mutation.rb

module Mutations
class BaseMutation < GraphQL::Schema::RelayClassicMutation;end
end

Next, I’ll add the app/graphql/mutations/create_user.rb file and write the logic for creating the user. We need to define a resolve method and define the arguments for our mutation and the fields which can be returned by it.

module Mutations
class CreateUser < BaseMutation
argument :name, String, required: true
argument :email, String, required: true
field :user, Types::UserType, null: true
field :errors, [String], null: true
def resolve(name:, email:)
user = User.new(name: name, email: email)
if user.save
{
user: user,
errors: []
}
else
# Failed save, return the errors to the client
{
user: nil,
errors: user.errors.full_messages
}
end
end
end
end

It’s quite easy to understand what’s happening here, the resolve method is used when a mutation is called and it’s responsible for performing the INSERT in the database and returning the result (or errors).

Next, we need to open the app/graphql/types/mutation_type.rbfile and ad the create_user mutation.

 field :create_user, mutation: Mutations::CreateUser

Let’s see how to use it. We simply send a mutation from graphiql.

mutation {
createUser(input: { name:"Luke Skywalker", email: "luke@lucas-films.com" })
{
user {
name
blogposts {
title
}
}
errors
}
}

We can see that the keyword changed from the query to mutation, next we specify the mutation we want to call and then we specify the input (name and email).

The next lines define what we expect to get from the mutation — a user type or some errors.

Create user mutation

▶ You can check the full commit here.

Conclusions and Next Steps

This was just a brief example on how to use GraphQL with Ruby on Rails, but make sure you check the GraphQL documentation because it has a lot more to offer.

Of course, there are some limitations, caching it’s harder to achieve, and n+1 queries may become an issue. Luckily there are solutions for this, like the goldiloader gem.

Also, sending files can be difficult, because encoding the files to base64 is time and resources consuming. Of course, you could always define an API for storing files and use it together with GraphQL.

GraphQL looks definitely promising, but it’s not mature enough to build applications just by using it, but I think used together with a REST API it can bring value and save time on complex projects.

You can check the entire code here where I added more mutations, error handling and examples.

Enough with back-end experiments. Curious how does it look like on the front-end side? Our tech lead wolf, Sasha, will teach you how to connect this API to Nuxt.js. We re about to publish the 2nd part of the article. Hit the “follow” button to be the first to get the insights.

Wolfpack Digital web developers found the way to apply GraphQL (back-end) and Nuxt.js (front-end) in Ruby on Rails
Applying GraphQL and Nuxt.js in Ruby on Rails

Want to know what Wolves are up to? Check our blog posts with tech trends, how-to articles, and tips for entrepreneurs.

Want to work with us? Because Wolfpack Digital is hiring.

Want us to build your app? Because Wolfpack Digital is the right app development agency for that.

--

--