🦒

jsonapi-serializerの基本的な使い方

2022/06/16に公開

jsonapi-serializer

  1. はじめに
  2. 検証環境の用意
  3. serializerを記述
  4. レスポンス構造を理解する
  5. 関連モデルの取得方法
  6. meta利用

1. はじめに

jsonapi-serializerは、Netflixが開発していたfast_jsonapiをforkしたライブラリである。fast_jsonapは、2022年現在メンテナンスが行われていない。

jsonapi-serializer

fast_jsonapi

Ruby用のシリアライズライブラリには他にActiveModelSerializerがある。jsonapi-serializer側のREADMEによれば、ActiveModelSerializerよりもruby hashの生成が25倍速いとのこと。本当だろうか。

以下にjsonapi-serializerの使い方をまとめておく。

2. 検証環境の用意

下記のようなモデルとDBを用意した。※timestampsカラムは記載省略

#  id         :integer          not null, primary key
#  name       :string
#  year       :date
#  owner_id   :string
class Movie < ApplicationRecord
  has_many :actors
  belongs_to :owner
end

#  id         :integer          not null, primary key
#  name       :string
#  age        :string
class Owner < ApplicationRecord
  has_one :movie
end

#  id         :integer          not null, primary key
#  name       :string
#  movie_id   :integer
class Actor < ApplicationRecord
end

3. serializerを記述

Movieの為のserializerを記述する。

class MovieSerializer
  include JSONAPI::Serializer
 
  attributes :name ※取得したいカラムを指定
end

4. レスポンス構造を理解する

適当なcontrollerを用意して、renderしてみる。

class HogeController  < ApplicationController
  def index
    movie = Movie.all
    json_string = MovieSerializer.new(movie).serializable_hash.to_json
    render json: json_string
  end
end

レスポンス結果

data	
  0	
    id	"1"
    type "movie"
    attributes	
       name "movie1"
  1	
    id	"2"
    type "movie"
    attributes	
      name "movie2"

各データにidとtypeが存在。カラムの値はattributes配下にある。これが基本的なレスポンス構造。

idとtypeは、set_id, set_typeオプションを使用することで、任意の値に変更が可能。ユースケースは少ないと思う為詳細は割愛。

5. 関連モデルの取得方法

Movieモデルに関連するActor及びOwnerを取得したい。

serializerを下記のように用意する。

class MovieSerializer
  include JSONAPI::Serializer

  attributes :name
  ※モデルでもアソシエーションを組んでおくこと
  has_many :actors 
  belongs_to :owner 
end

class ActorSerializer
  include JSONAPI::Serializer

  attributes :name
end

class OwnerSerializer
  include JSONAPI::Serializer

  attributes :name
end

レスポンス結果

0	
  id "1"
  type "movie"
  attributes	
    name "movie1"
  relationships	
    actors	
      data	
         0	
	   id "1"
	   type	"actor"
	 1	
	   id "2"
	   type	"actor"
    owner	
      data	
	id "1"
	type "owner"
1	
  id "2"
  type "movie"
  attributes	
    name "movie2"
  relationships	
    actors	
      data
 	0
	  id "3"
	  type "actor"	
     owner	
      data	
	id "2"
	type "owner"

relationshipsカラムが追加され、関連モデルのidとtypeが取得出来た。が、関連モデルのレコードが存在していない。actorとownerのnameを取得したい。controllerを下記のように変更する。

class HogeController  < ApplicationController
  def index
    movie = Movie.all
    json_string = MovieSerializer.new(movie, options).serializable_hash.to_json
    render json: json_string
  end

  private

  def options
    options = {}
    options[:include] = [:actors, :owner]
    options
  end
end

レスポンス結果

data	
  0	
   id "1"
   type	"movie"
   attributes	
     name "movie1"
   relationships	
     actors	
	data	
	  0	
	    id "1"
	    type "actor"
	  1	
	    id "2"
	    type "actor"
     owner	
	data	
	  id "1"
	  type "owner"
  1	
    id "2"
    type "movie"
    attributes	
      name "movie2"
    relationships	
      actors	
        data
 	  0
	    id "3"
	    type "actor"	
      owner	
	data	
	  id "2"
	  type "owner"
included	
  0	
   id "1"
   type	"actor"
   attributes	
     name "actor1"
  1	
    id "2"
    type "actor"
    attributes	
      name "actor2"
  2	
    id "1"
    type "owner"
    attributes	
      name "owner1"
  3	
     id	"2"
     type "owner"
     attributes	
       name "owner2"

included配下に関連モデルのレコードが取得出来ている。

6. Meta

metaを使うことで、各データに追加の値をレスポンスに含めることが出来る。

serializerを変更する。

class MovieSerializer
  include JSONAPI::Serializer

  attributes :name
  has_many :actors
  belongs_to :owner
  meta do |movie|
    {
      years_since_release: Date.current.year - movie.year 
    }
  end
end

レスポンス結果

data	
  0	
   id "1"
   type	"movie"
   attributes	
     name "movie1"
   relationships	
     actors	
	# 省略
    owner	
	# 省略
    meta	
      years_since_release 12 # 追加される
  1	
    id "2"
    type "movie"
    attributes	
      name "movie2"
    relationships	
      actors	
	# 省略
      owner	
	# 省略
    meta	
      years_since_release	22 # 追加される
included	
# 省略

第2引数に渡しているoptionsハッシュに、metaをキーとして含める。これにより、トップレベルにmetaカラムをレスポンスとして返すことが可能。

class HogeController  < ApplicationController
  def index
    movie = Movie.all
    json_string = MovieSerializer.new(movie, options).serializable_hash.to_json
    render json: json_string
  end

  private

  def options
    options = {}
    options[:meta] = { total: 2 }
    options[:include] = [:actors, :owner]
    options
  end
end

レスポンス結果

data	
  0	
    id "1"
    type "movie"
    attributes	
      name "movie1"
    relationships	
      # 省略
  1	
    id "2"
    type "movie"
    attributes	
      name "movie2"
    relationships	
      # 省略
included	
  # 省略
meta
  total: 2

基本的な使い方はこんなところでしょうか。

Discussion