Rails building json API responses with JBuilder

Rails is a MVC web application framework which supports building complex websites without writing any APIs. But, client side libraries are evolving at brisk pace with wide-spread use of React JS, AngularJS, VuJS etc. Thus, building API endpoints is a very important tasks these days.

Rails has been pretty adoptive when it comes to supporting what community is up to. Rails started supporting API only application from Rails 5. There are quite a few options to build json response in Rails application. Listing down a couple of widely used gems to build them.

Both of them have their pros and cons to consider. In this article, we will just consider building json API response with jbuilder.

JBuilder

Jbuilder is quite useful when it comes to generating and rendering JSON responses for API requests in Rails. This article helps understand, how to render JSON responses in general. Jbuilder is particularly good at following things:

  • Reusable JSON API responses through partials
  • View helpers available when generating API responses
  • Convention over configuration principle in action

We will also take a look at rendering json reopnses from controller with JBuilder. Then, reusing same JSON reponse in jbuilder view file and models.

Rails API only application

Rails API only application is a slimmed down version of Rails application. It does not contain gems that are usually required for front-end specific implementation. For e.g. coffee rails, turbolinks etc.

Ruby / Rails Versions

Versions used in building this application are listed below.

  • Ruby: 2.5.3
  • Rails: 5.2.1
1. Create Rails API only application

Let us create an API only Rails application with the help of command given below.

rails new build-api-with-jbuilder --api
  1. --api option takes care of setting up Rails application to be api only application.

  2. This command also performs bundle install to resolve dependencies and install them in order to run the application.

2. Add jbuilder gem

Rails API only app that is generated in Step 1, has following lines in commented format as given below.

# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
# gem 'jbuilder', '~> 2.5'

In order to use jbuilder to build/format json, we need to uncomment those two lines or add

gem 'jbuilder', '~> 2.5'

to Gemfile.

Bundle install to install the gem.

3. Create Data Model

In order to demonstrat how to build APIs with API only Rails application, let us create a few tables and insert data into them.

rails g model Category name:string
rails g model Source name:string
rails g model Article title:string url:string source:belongs_to category:belongs_to

Once, we run generators to create migrations and models, let’s run these migrations.

rails db:migrate
4. Insert data

We will use faker to quickly add some dummy data to the data model that we created in Step 3.

Add gem faker to Gemfile.

# Gemfile
gem 'faker', '~> 1.9.1', group: [:development, :test]

We will just use faker gem to generate some fake data in development and test environments. Then, perform

bundle install

to install faker gem and to use it with our application.

We will add fake data using seeds.rb

# seeds.rb

# Create Categories
10.times { Category.create!(name: Faker::Lorem.word) }

# Create sources
10.times { Source.create!(name: Faker::Company.name) }

# Create Articles
50.times {
  category = Category.all.sample
  source = Source.all.sample
  Article.create!(
    title: Faker::Lorem.sentence,
    url: Faker::Internet.url,
    category: category,
    source: source
  )
}

Run database seed data generation with the command given below.

rails db:seed

Render JSON responses with JBuilder

Now that we have Rails API only application ready with jbuilder and some data in place, we can use jbuilder to repond with json to API requests.

Render array in API response with JBuilder

Let’s say we want a list of categories in an API request.

Step 1. Create categories controller.

rails g controller categories

Step 2. Setup route for API endpoint

# config/routes.rb
resources :categories

This step will setup RESTful routes for categories resource.

Step 3. Create controller action

# app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
  def index
    @categories = Category.all
  end
end

Step 4. Create index.json.jbuilder file in category views

Create a directory categories if it does not exist. Run the command given below from project root.

mkdir -p app/views/categories

Create a file index.json.jbuilder in app/views/categories directory.

# app/views/categories/index.json.jbuilder
json.array! @categories do |category|
  json.id category.id
  json.name category.name
  json.created_at category.created_at
end 

Step 5. JSON response from jbuilder

To verify the response.

  • Start the rails server.
rails s
  • Request to categories API endpoints
curl -X GET http://localhost:3000/categories.json

JSON response will be something like,

[ 
    {"id":11,"name":"perspiciatis","created_at":"2018-11-10T12:17:21.678Z"},
    {"id":12,"name":"fugit","created_at":"2018-11-10T12:17:21.683Z"}
]

Obviously, the above listed json is a trimmed down version of the original response.

Rendering Partials in API response with JBuilder

We can use partials to render json response which is required in multiple APIs.

Let’s say, we want a list of articles in an API endpoints.

Step 1 Create ArticlesController

Create ArticlesController with the help of Rails generator with command given below.

rails g controller articles

Step 2: Setup Routes for articles resource

Setup routes for *Article resource with the help of command given below.

# config/routes.rb
resources :articles

Step 3. Create controller action

# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles= Article.all
  end
end

Step 4. Create index.json.jbuilder file in articles views

Create a directory articles if it does not exist . Run the command given below from project root.

mkdir -p app/views/articles

Create a file index.json.jbuilder in app/views/articles directory.

# app/views/articles/index.json.jbuilder
json.array! @articles do |article|
  json.id article.id
  json.title article.title
  json.url article.url
  json.created_at article.created_at
end

Step 5. JSON response from jbuilder

To verify the response.

  • Start the rails server.
rails s
  • Request to categories API endpoints
curl -X GET http://localhost:3000/articles.json

JSON response will be something like,

[
  {
    "id": 1,
    "title": "Sint maxime et unde.",
    "url": "http://mante.io/travis_klocko",
    "created_at": "2018-11-10T12:21:20.376Z"
  },
  {
    "id": 2,
    "title": "Soluta est beatae cum.",
    "url": "http://blick.biz/alexis",
    "created_at": "2018-11-10T12:21:20.381Z"
  }
]

Note: The response given above is limited to 2 articles.

Next, let us add a category for each article in json with partial in Jbuilder

Step 6 Create partials jbuilder for category

Create a partial view file in app/views/categories directory, by name _category.json.jbuilder

# app/views/categories/_category.json.jbuilder
json.id category.id
json.name category.name
json.created_at category.created_at

Step 7 Render partial in Article json jbuilder file

We can call partial in jbuilder to generate json as given below.

json.array! @articles do |article|
  json.id article.id
  json.title article.title
  json.url article.url
  
  json.category do
    json.partial! 'categories/category', category: article.category
  end
  
  json.created_at article.created_at
end

This will render category for each article, when articles.json is called.

curl -X http://localhost:3000/articles.json

Response:

[
  {
    "id": 1,
    "title": "Sint maxime et unde.",
    "url": "http://mante.io/travis_klocko",
    "category": {
        "id": 13,
        "name": "ut",
        "created_at": "2018-11-10T12:17:21.685Z"
    },
    "created_at": "2018-11-10T12:21:20.376Z"
  },
  {
    "id": 2,
    "title": "Soluta est beatae cum.",
    "url": "http://blick.biz/alexis",
    "category": {
      "id": 20,
      "name": "animi",
      "created_at": "2018-11-10T12:17:21.700Z"
    },
    "created_at": "2018-11-10T12:21:20.381Z"
}
]

Note: Response is limited to 2 results.

As we can see, each article node in the json response contains category node with details of the category. This gets rendered by the jbuilder partial which was generated for category.

Feel free to comment down with your thoughts. Thanks for reading!

References: