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