Keeping the pace with changing technologies and dependencies is the hardest part in developer's live. The "ActiveModel .Serializers" gem is no longer supported, so we looked for an alternative - this time Netflix comes with help.
ActiveModelSerializers Not updated anymore!
When JSON API format for API responses become a standard, it started to be clear that projects need a nice object serialization solution for unifying code across the whole code base. For a long time I used the ActiveModelSerializers gem for that, but unfortunately, that is not updated anymore.
Because of that I looked for alternatives and found that the best candidate to replace obsolete gem is Fast JsonAPI gem delivered by Netflix.
Ruby On Rails REST API
The complete guide
Create professional API applications that you can hook anything into! Learn how to code like professionals using Test Driven Development!
Take this course!Moving from ActiveModelSerializers to Fast JSON API
If you have an existing application that uses activemodel_serializers gem and you want to move into the fast_jsonapi, you won't have too much of troubles. Both gems are pretty similar in concept. you define a serializer for each processed resource and you use it in the controller to transform your Ruby objects into JSON hashes in an appropriate structure.
Modulized approach instead of inheritance
First of all, let's take a look what is different in both of those gems:
# ActiveModelSerializers approach
class ArticleSerializer < ActiveModel::Serializer
attributes :id, :title, :content, :slug
end
In the example above we have the ArticleSerializer class which inherits from ActiveModel::Serializer class to apply expected behavior.
# Fast JSON API approach
class ArticleSerializer
include FastJsonapi::ObjectSerializer
attributes :title, :content, :slug
end
As you can see, there are two key differences.
First of all, you need to include the FastJsonapi::ObjectSerializer instead of inherits from the base gem. This is not a problem if you'll use the application serializer as the base serialization class for your application and inherits from it.
In that approach you would only need to apply this change in one file:
# Fast JSON API approach
class ApplicationSerializer
include FastJsonapi::ObjectSerializer
end
class ArticleSerializer < ApplicationSerializer
attributes :title, :content, :slug
end
No :id in attributes
You probably noticed, that in the second example there is no :id key listed in attributes. That's because the fast_jsonapi gem requires :id by default on any object you pass in through initialization.
# ActiveModelSerializers approach
attributes :id, :title, :content, :slug
# Fast JSON API approach
attributes :title, :content, :slug
No default serializer in controllers
When we used ActiveModelSerializers gem our controller used a serializer that matched our object class by default and personally I liked it more. Thanks to that we could not bother with serializers at all in our controllers keeping them nice and clean:
class ArticlesController < ApplicationController
def index
render json: Article.all
end
def show
render json: Article.find(params[:id])
end
end
Now we need to explicitly define which serializer we want to use by wrapping the rendered result into the new instance of the serializer class.
class ArticlesController < ApplicationController
def index
render json: serializer.new(Article.all)
end
def show
render json: serializer.new(Article.find(params[:id]))
end
private
def serializer
ArticleSerializer
end
end
Overall I don't think it's too much effort, especially because in every case the serializer initialization looks completely the same, and that allows us to write helper methods that do that for us. However, if you have a big application, you could avoid changing dozens of controllers and writing additional code for each action you add to your application by overriding the render method.
# app/controllers/application_controller
def render(options={})
options[:json] = serializer.new(options[:json])
super(options)
end
Thanks to this change you won't need to do any change in your controllers except defining the serializer method.
Manually added extra parameters
If you want to add extra parameters, like metadata or links, they need to be explicitly passed via the options hash. I wrote a whole article guiding how to add links and metadata to the serialized response as it's quite a wide topic.
Summary
It's always hard to keep up to date with trends and dependency updates and we can't avoid such refactoring in our applications from time to time. When we need to do it, however, it's nice to change it the fastest way possible. It's nice to have your application written in a way that supports such changes without too much effort. Here are a few tips I found useful every time I change any gem I use for my application, rewritten for this serialization stuff.
- Use the base ApplicationSerializer where you extract any stuff dependent on other libraries.
- Don't put logic into your controllers.
- Name your serializers, models and all other classes in a unified way.
- Keep it DRY
And which gem do you use to serialize API responses? Share in the comments!
Special thanks
- freestocks for the great cover photo