Netflix製のjsonシリアライザgem fast_jsonapiを試す

先日OpenAPIのスキーマからRubyのクラスを自動生成するgemを作りました。

OpenAPIのschema定義からRubyのクラスを生成するgem「openapi2ruby」をつくりました - Start Today Technologies TECH BLOG

このgemを作って自動生成しようとしたのがActiveModel::Serializer(AMS)のシリアライザで
他にも自動生成できるものがないか調べていたときに、ちょっと前に話題になったNetflixのgemを見つけたので使ってみることに。

github.com

なんでも

serialization time is at least 25 times faster than Active Model Serializers on up to current benchmark of 1000 records.

らしい。速い。

サンプルアプリケーション作成

# Gemfile
gem 'fast_jsonapi'

先述の会社ブログのサンプルにならい User has_one Profileなモデルを持つRailsアプリを作成。
User.name, Profile.descriptionなフィールドをそれぞれ持つ。

# user.rb
class User < ApplicationRecord
  has_one :profile
end

# profile.rb
class Profile < ApplicationRecord
  belongs_to :user
end

それぞれに対応するシリアライザを作成

# user_serializer.rb
class UserSerializer
  include FastJsonapi::ObjectSerializer

  has_one :profile, serializer: ProfileSerializer
  attributes :name

  # カスタムattributeの定義も可能
  attributes :name_with_id do |object|
    "#{object.id}: #{object.name}"
  end
end

# profile_serializer.rb
class ProfileSerializer
  include FastJsonapi::ObjectSerializer

  belongs_to :user, serializer: UserSerializer
  attributes :description
end

最後にControllerから呼び出す

# users_controller.rb
class UsersController < ApplicationController
  def show
    user = User.find(params[:id])
    options = { include: [:profile] }
    serializer = UserSerializer.new(user, options)
    render json: serializer.serialized_json
  end
end

ブラウザでアクセスすると...

{
    "data": {
        "id": "1",
        "type": "user",
        "attributes": {
            "name": "takanamito",
            "name_with_id": "1: takanamito"
        },
        "relationships": {
            "profile": {
                "data": {
                    "id": "1",
                    "type": "profile"
                }
            }
        }
    },
    "included": [
        {
            "id": "1",
            "type": "profile",
            "attributes": {
                "description": "プロフィールです"
            },
            "relationships": {
                "user": {
                    "data": {
                        "id": "1",
                        "type": "user"
                    }
                }
            }
        }
    ]
}

所感

AMSとほぼ同じ感覚でjsonシリアライズが簡単にできた。

サンプルでも触れたCustom Attributesがブロックで簡単に書けたり
Conditional AttributesConditional Relationshipsなど便利機能も多くて助かる。

AMSと大きく異なる点が、READMEに書かれてる通り
デフォルトで生成するのがJSON:APIに準拠したjsonなところ。

シリアライズするオブジェクトに id, typeというフィールドが必須だったり、いくつか制約がある模様。
ActiveRecordのオブジェクトをシリアライズするのはいいが、プレーンなRubyオブジェクトをシリアライズするときに id相当のものが無くて困る。

気になってAMSのREADMEも読んでみると、どうやら開発中のバージョン1.0ではAMSでもJSON:APIに準拠するシリアライザになるとのこと。

The serializer will essentially be for defining a basic JSON:API resource object: id, type, attributes, and relationships.

GitHub - rails-api/active_model_serializers: ActiveModel::Serializer implementation and Rails hooks

fast_jsonapi同様、シリアライザはJSON:APIを意識したものが多いようなので追って調べてみる。