/ ruby

Active Model Serializer vz Jbuilder vz Rabl vz Grape-entity for rendering JSON

When architecting an API only application one the of the most important points of discussion among the team members is which framework to use ?

  • Should we be using Rails and render JSON ?
  • Should we be using Grape ?
  • Should we be using Rails-API ?

Also, how are we gonna format the JSON responses? Options that usually pop up include:

  • Jbuilder
  • ActiveModelSerializer
  • Rabl
  • Grape-Entity

Anyways I am not gonna favour one over the other in this article, the choice of these options entirely depend on the use case, but instead, I will run via each of the options quickly to give a basic idea of each.

Jbuilder

Jbuilder is bundled with Rails, and so it's one of the most popular choices. Jbuilder provides a nice DSL to format and structure your JSON response. It provide us with an easy way to define exactly what attributes are included in and how the response is formatted and nested. For generating json responses we need to create correspon corresponding /app/views/ directories just like you would with view templates but with the extension .json.jbuilder

# app/views/article/show.json.jbuilder
json.content format_content(@article.content)
json.(@article, :created_at, :updated_at)

json.author do
  json.name @article.author.name.familiar
  json.url url_for(@article.author, format: :json)
end

RABL

Another alternative is RABL, it also provides a custom DSL for generating JSON responses. It works by creating a view with the extension .rabl, and defining which attributes, nodes, and relations you wish to include in the JSON response.

# app/views/posts/index.rabl
collection @posts
attributes :id, :title, :subject
child(:user) { attributes :full_name }
node(:read) { |post| post.read_by?(@user) }
Active Model Serializer

Active Model Serializer is a great way to build JSON responses using an object oriented approach. It separates the serialization concern into its own folder /app/serializers, comes with its own Rails generator, and it behaves more like ActiveRecord in that you can define associations in the serializer.
It also allows you to choose your adapter-to decide what type of JSON structure is produced-or to build your own. Popular supported formats are JSON-API and JSON-HAL. It can also act as a presenter where you can define custom methods to display extra information or override how it’s displayed in your JSON.

ActiveModelSerializer and Rails 5 - API mode

With Rails 5, rails-api comes in bundled and when you generate a API only Rails app with ActiveModelSerializer is the default choice.

class PostSerializer < ActiveModel::Serializer
  attributes :title, :body
  has_many :comments
  url :post
end
Grape Entity

Grape Entity was extracted from Grape, which is a popular gem used for building RESTful APIs. Similarly to RABL and Jbuilder, it provides a DSL for defining entities which are the structure of your JSON response.

module API
  module Entities
    class Article < Grape::Entity
      expose :title
      expose :content, documentation: { type: "Text", desc: "Blog post." }
      expose :author_info do
        expose :email
        expose :full_name
      end
    end
  end
end
ROAR

ROAR allows you to build presenter classes to represent your data. It also supports JSON and XML responses.

require 'roar/json'

module PostRepresenter
  include Roar::JSON
  property :title
end
ActiveModel or Plain Ruby Hash

This may seem like a strange thing to point out, but for very simple cases, you can simply call the to_json method on either an ActiveModel object or a native Ruby Hash.

# Using an @organization model
respond_to do |format|
  format.json do
    render json: @organization.to_json
  end
end
# Using a plain Ruby Hash
respond_to do |format|
  format.json do
    render json: {
      name: @user.name,
      email: @user.email
    }.to_json
  end
end
Benchmarks

Kirill Platonov has an interesting benchmark with ActiveModelSerializer vz Jbuilder. The following is an excerpt from his article

You can see everything by yourself. Jbuilder wins ActiveModel::Serializers only in the standalone variant of usage and only when use transform only single AR object, not an array. But the difference between Jbuilder and AMS in this case only 1.06x, it's very close to calculating error.

And from opposite you can see, that in all other cases Jbuilder is much slower than ActiveModel::Serializers. And it's the real world cases because Jbuilder is mostly used with render method. And the results with render method are extremely bad for Jbuilder:

11.95x slower than AMS with a single object

8.94x slower than AMS with array of objects

I think for now there is really no reason to use Jbuilder. It's very slow, too verbose and too complex for such simple task as transforming objects to JSON. You can use ActiveModel::Serializers and it will be handy and will cover all of your usage cases.

Conclusion

Now that you have various options at hand, I leave you to decide what is the best suited for your app.

Already know you that which you need.
-- Yoda

Manu S Ajith

Manu S Ajith

Tech Entrepreneur, dating Elixir, in long-term ❤️ w/ Ruby, had multiple one night stands w/ Go. Into functional paradigms DDD/CQRS/EventSourcing architecture these days. @manusajith on the interwebs

Read More