Serializr is a library for creating canonical JSON representation of objects for your RESTful APIs.
Think of the serializers as the view layer of your application. They are not the only JSON representation of an object, but they are the representation you wanna show to the API.
Add this line to your application's Gemfile:
gem 'serializr'Using the serializr library is pretty simple. To generate your first serializer, execute:
$ rails generate serializr User id name email
The output should hint that the generator created two files:
create app/serializers/application_serializer.rb
create app/serializers/user_serializer.rb
The app/serializers/user_serializer.rb file should contain:
class UserSerializer < ApplicationSerializer
attributes :id, :name, :email
endThis says: expect the object to be serialized to respond to #id, #name and
#email and show the resulting JSON as:
{
"id": 42,
"name": "John Doe",
"email": "[email protected]"
}Oh, wait... Your users don't respond to #name?
class UserSerializer < ApplicationSerializer
attributes :id, :name, :email
def name
"#{object.first_name} #{object.last_name}"
end
endThat's fine. Your serializers can render fields your object don't respond to.
Now, to render the JSON object, you need to say the following in your controller:
class UsersController < ApplicationController
def show
user = User.find(params[:id])
render json: user
end
endThe serializr library hooks itself into ActionController::Base or
ActionController::API and it can infer the UserSerializer out of the User
object. You can also be explicit, in which case the inferring logic won't be
triggered at all.
class UsersController < ApplicationController
def show
user = User.find(params[:id])
render json: user, serializer: UserSerializer
end
endYou can also render collections of objects:
class FriendsController < ApplicationController
def index
friends = User.friends_of(params[:id])
render json: friends
end
endBeing explicit here may have performance benefits, as to guess the Serializer
class to use, we need to unroll the collection. The explicit usage, unarguably,
looks pretty awesome as well, so you can wow your friends! Which, is always
cool, you know. 😎
class FriendsController < ApplicationController
def index
friends = User.friends_of(params[:id])
render json: friends, serializer: UserSerializer[]
end
endAnd this is how you drop Action View off your API's, kids!
To fill the API cliché, we need to go over one last file:
app/serializers/application_serializer.rb. At first, it looks like this:
class ApplicationSerializer < Serializr
endThe grown ups call it Layer
Supertype. We'll call
it that thing that looks like ApplicationController and serves the same
purpose, but for the serializers, not the controllers. You can use it to put
common utilities shared by all the serializers.
For example:
class ApplicationSerializer < Serializr
# You may need the routes helpers, so you can link between resources in your
# JSON responses.
include Rails.application.routes.url_helpers
cattr_reader :serializer_class_cache do
Hash.new do |hash, cls|
hash[cls] = "#{cls}Serializer".constantize
end
end
# Because I'm sure you gonna ask: how do I render associations. Where are the
# `has_one` and `has_many` class macros?
#
# The answers is: you don't need those macros. You can use similar methods
# like the ones below to render the associations with plain old boring Ruby
# methods.
#
# class UserSerializer < ApplicationSerializer
# attributes :card
#
# def card
# render_one(object.credit_card)
# end
# end
#
# No extra DSL, but still: clean, consise and flexible view code.
def render_one(object, serializer: nil)
return if object.nil?
serializer ||= serializer_class_cache[object.class]
serializer.new(object)
end
def render_many(objects, serializer: nil)
return [] if objects.blank?
serializer ||= serializer_class_cache[objects.first.class][]
serializer.new(objects)
end
endSerializr? Really? I know. It's fine.
You can require serializr, you can require serializer as well. The
constants? Both of Serializr and Serializer point to the same thing. Same
for the generators. Use whatever your brain and 🖐 (fingers) like.
Bug reports and pull requests are welcome on GitHub at https://github.com/gsamokovarov/serializr. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.