jsonapi-serializerの基本的な使い方
jsonapi-serializer
- はじめに
- 検証環境の用意
- serializerを記述
- レスポンス構造を理解する
- 関連モデルの取得方法
- meta利用
1. はじめに
jsonapi-serializerは、Netflixが開発していたfast_jsonapiをforkしたライブラリである。fast_jsonapは、2022年現在メンテナンスが行われていない。
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