Railsでjsonapi-serializer使ってみた

Railsでjsonapi-serializer使ってみた

はじめに

api仕様を決めるのに苦労していませんか?
今回は規則的にapiの型等を決定できる手法をご紹介します。

json-api-serializerとは

jsonapi-serializerは、RubyにおけるJSON:APIのserializerのことです。
特徴は以下の通り。

  • Active Model Serializerと似た宣言構文
  • belongs_to, has_many, has_oneというrelationsをサポート
  • includedを利用して、複合的な文書をサポート
  • 複合的な文書の最適化されたシリアライゼーション
  • キャッシング

JSON:APIとは

apiを設計する際のJSONフォーマットを定めたものです。
例えば、以下のようなものです。

{
  "links": {
    "self": "http://example.com/articles",
    "next": "http://example.com/articles?page[offset]=2",
    "last": "http://example.com/articles?page[offset]=10"
  },
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    },
    "relationships": {
      "author": {
        "links": {
          "self": "http://example.com/articles/1/relationships/author",
          "related": "http://example.com/articles/1/author"
        },
        "data": { "type": "people", "id": "9" }
      },
      "comments": {
        "links": {
          "self": "http://example.com/articles/1/relationships/comments",
          "related": "http://example.com/articles/1/comments"
        },
        "data": [
          { "type": "comments", "id": "5" },
          { "type": "comments", "id": "12" }
        ]
      }
    },
    "links": {
      "self": "http://example.com/articles/1"
    }
  }],
  "included": [{
    "type": "people",
    "id": "9",
    "attributes": {
      "firstName": "Dan",
      "lastName": "Gebhardt",
      "twitter": "dgeb"
    },
    "links": {
      "self": "http://example.com/people/9"
    }
  }, {
    "type": "comments",
    "id": "5",
    "attributes": {
      "body": "First!"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "2" }
      }
    },
    "links": {
      "self": "http://example.com/comments/5"
    }
  }, {
    "type": "comments",
    "id": "12",
    "attributes": {
      "body": "I like XML better"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "9" }
      }
    },
    "links": {
      "self": "http://example.com/comments/12"
    }
  }]
}

元々は、fast_jsonapiと呼ばれていたものをアップデートして受け継いだものです。

fast_jsonapiとは

fast_jsonapiとは、NetflixがOSSとして開発していたgemでJSONのserializerです。
fastとついているほどなので、高速なレスポンスを提供しているようです。
現在はこのプロジェクトは止まっており、全て上記のjson_serializerに継承されています。

ところでserializeとは

IT用語辞典によると、

シリアライズとは、複数の要素を一列に並べる操作や処理のこと。単にシリアライズといった場合には、プログラムの実行状態や複雑なデータ構造などを一つの文字列やバイト列で表現する「直列化」を指すことが多い。

らしいです。
今回の文脈におけるserializeは、あるデータを一定の規則に沿って整形することを指します。
railsの例で言うと、Modelの構造(attirbutesやrelations)に沿って決まりきった形式でデータを整形することを表します。

使い方

前提

次のような三つのモデルがあったとします。

  • 学校
  • 生徒
  • 科目
学校
生徒
科目
# app/models/school.rb
class School < ActiveRecord::Base
  has_many :students
end

# app/models/student.rb
class Student< ActiveRecord::Base
  belong_to :school
  has_many :subjects

  validates :name, presence: true
end

# app/models/subject.rb
class Subject< ActiveRecord::Base
  belong_to :student
end

gemをインストール

Gemfileに以下追記。

# Gemfile
gem 'jsonapi-serializer', '~> 2.2'

Serializerを記述

次のポイントに気を付けて、記述。

  • relations(has_many, had_one, belongs_to)
  • attributes

仮に StudentのSerializerを作成する場合は、以下のように記述してください。

# app/serializers/student_serializer.rb

class StudentSerializer
  include JSONAPI:Serializer

  belongs_to :school, lazy_load_data: true, serializer: SchoolSerializer
  has_many :subjects, lazy_load_data: true, serializer: SubjectSerializer
  attributes :name
end

もちろん、Studentの関係性をもつモデルのSerializerも必要になります。

使ってみた感想

「実装コスト」「可読性」「パフォーマンス」が改善されました。
特に、「実装コスト」が大幅に改善され、圧倒的に楽になりました。
今までは、毎度apiを作成する際にjsonフォーマットを決めていたので、かなり苦労していましたが、そのコストが0になったという印象。
さらに、Model通りのrelations, attributesをapiとして返すことが可能ですので、全体的に統一感が出ました。ソースコードとしても、かなり規則的でリーダブルなものになったと思います。
一方で、apiを使用する側はparseするのが少し大変そうと思ったり…。

Next Post