Rails での JSON API 実装まとめ
前後リンク
- RESTful API のおさらい
- Rails での JSON API 実装まとめ
- スキーマファースト開発
- The NEXT of REST
Ruby on JSON
の図のような流れになるんですが、それぞれ見ていきます。
to_json (2011-2013 頃)
2011-2013 年頃、僕らは render :json
を使っていました。
render json: @user
render json: @user.to_json
として User#as_json
や User#to_json
を利用します。
この頃はまだ SPA という言葉もなく、ネイティブアプリもそこまで流行っていなかったので これで十分だったのですが、どんどん API に世の中が寄っていき、限界を迎えます。
この頃のツラみ
- JSON を組み立てるのが大変
- 何が返るのか分からない
- 「リソース」の存在を強制できていない
- テストが大変
JSON Template engines (2013-2015 頃)
JSON を組み立てる方法として、RABL や jbuilder といった JSON 用のテンプレートエンジンを使う方法が出てきます。
RABL : 2011年からある老舗の gem。独特の言語で記述する必要があるので学習コストが高め。
jbuilder : rails4 から標準になった。割と簡単に柔軟に書ける。
どちらも「JSON は view」という考え方で、 controller では普通に model を assign して、view で JSON を render する。
この頃のツラみと解決
- JSON を組み立てるのが大変
- JSON を組み立てる用の DSL によって解決した!
- 何が返るのか分からない
- 変わらず大変だけど、view を見れば分かるので少し分かりやすくなった
- ghost_writer や autodoc でドキュメントを自動生成するようになる
- 「リソース」の存在を強制できていない
- 部分テンプレートに分割することでリソースを表現可能に
- だが jbuilder の部分テンプレートは異常に遅いのだった……!!
- テストが大変
- 変わらず大変
- rspec-json_matcher や strong_json で頑張る
ActiveModelSerializers (2014-)
jbuilder は部分テンプレートのレンダリングが異常に遅く、 例えばユーザデータ 200 件を含む JSON を返したいだけで 50ms 以上食われることがザラにあった。
このため、遅いところでは「インラインに展開する」とか「to_json
を使う」とかを頻繁に行っていて、
これを解決するために serializer 層が生まれた。
AMoS はその流れで出てきたライブラリで、
- app/serializers 以下に置くので HTML と混ざらない
- 単体でテストが書ける
という serializer としてのメリットと、
- HogeSerializer を定義するだけで使える簡便性
- DSL チックじゃないので書きやすくて読み易い
という利点、あと何より速さで使われ出した。
render json: @user
class UserSerializer < ActiveModel::Serializer
attributes :id,
:name,
:birthday
def birthday
object.created_at.strftime("%Y/%m/%d")
end
end
この頃のツラみと解決
- JSON を組み立てるのが大変
- 更に簡単になった!
- 何が返るのか分からない
- かなり読みやすいので、「サーバの実装が正」が許される状況なら autodoc 等のドキュメンテーションツールがなくても「実装読んでね」が使えるかも?
- 「リソース」の存在を強制できていない
- Serializer がリソースになるので解決
- テストが大変
- 相変わらず面倒です……。
- jbuilder の異常に遅い partial rendering
- 普通の速度で返せるようになった
Grape (2012-2014 頃)
この流れとは別に、Grape が存在しました。 REST API を作成するためのマイクロフレームワークです。
class UserEntity < Grape::Entity
expose :id
expose :name
expose :birthday
end
class API < Grape::API
format :json
resources :users do
get ":id" do
present User.find(params.id), with: UserEntity
end
end
end
grape の記法を学ばなければならず、学習コストは高い。 DSL だけあって、API 定義 (Entity) と router は割と読みやすいので慣れれば楽かも。
この頃のツラみと解決
- JSON を組み立てるのが大変
- 簡単になった!
- 何が返るのか分からない
- かなり読みやすいので、「サーバの実装が正」が許される状況なら autodoc 等のドキュメンテーションツールがなくても「実装読んでね」が使えるかも?
- 「リソース」の存在を強制できていない
- Entity がリソースです
- テストが大変
- 相変わらず面倒です……。
AMoS と同じように問題を解決しているんだけど、 いかんせん独自フレームワーク、独自 DSL だったのがネックですね。 Rails じゃないと使われないという悲しみがあるのでした。
JSON Schema (2014-2016 頃)
JSON Schema とは: JSON で表現されるデータに対してデータ定義する Schema を記述する仕組み。
超簡単な例だと以下のようなデータと schema 定義。(概念コードです
{
"id": 12345678,
"name": "Taro",
"birthday": "2000-01-01 00:00:00"
}
properties:
id:
type: integer
name:
type: string
birthday:
type: date-time
この頃のツラみと解決
- JSON を組み立てるのが大変
- JSON Schema は直行する概念なのでどんな JSON 生成技術とも一緒に使えます
- 何が返るのか分からない
- 返す JSON のスキーマを書いていくので、まさに「何を返すか」が分かります
- スキーマがあるので、HTML ドキュメントも自動生成することができます。
- 「リソース」の存在を強制できていない
- これも JSON 生成処理次第
- テストが大変
- ここが解決します!
- スキーマをデータの検証に使うことができます
- 入力値や、返した値が仕様を満たしているかどうかのテストを書けるようになった
- すべての request/response を機械的にチェックすることで仕様と実装の乖離が生まれない状況が作れる
また、他に
- JSON/YAML なので Ruby が分からなくても書ける
- サーバ担当が書くまで決まらないという流れからの脱却。 インタフェースを決めた段階で、誰でもスキーマを記述することができます。
- API Client が作れる
- サーバがどんなリクエストを要求しているかのスキーマがあるので、 リクエストを投げる側のメソッドを自動生成することができます
といった辺りも大きなメリットです。
先駆者たち
DeNA、Cookpad 等。2014年の中頃辺りから盛り上がってきた。
- JSON Schema と API テスト YAPC::Asia Tokyo 2014
- 全てがJSONになる - ✘╹◡╹✘
- Qiita API v2のJSON Schemaを公開しました - Qiita Blog
API Description Language (2016-)
JSON Schema は基盤となり、JSON Schema の上で API を記述する言語が生まれてきます。
JSON Schema は「JSON の構造を定義できる」だけで、API として使う JSON」の定義は JSON Schema の上にもう一つレイヤーが必要。
そこで出てきたのが以下の諸々で、現在 5 派閥ぐらいありそうです。
- API Blueprint
- apiary で使われているスキーマ定義
- OpenAPI
- 最大派閥っぽい
- Swagger で使われているスキーマ定義
- RAML
- チャットワークAPIドキュメント で使われています
- JSON Hyper-Schema
- 生 JSON Schema
だいたい全て
- markdown とか YAML とかの書き易いツールで API 定義を書いたら
- ドキュメントがめっちょ綺麗に出力されて
- mock サーバも勝手にできて
- ドキュメントの HTML 上からでも request/response を実際に投げてチェックできる
みたいな機能を備えてます。
この頃のツラみと解決
- JSON を組み立てるのが大変
- どんな JSON 生成技術とも一緒に使えます
- 何が返るのか分からない
- 更に読みやすくなりました!
- 「リソース」の存在を強制できていない
- リソースを記述できるようになりました!
- テストが大変
- こちらも引き続き改善されています
当時ツラかった内容が全て解決していますね。
参考URL
- API Blueprintとその周辺ツール - Qiita
- 僕が考えた最強のAPIドキュメント生成 - 銀の人のメモ帳
- GoConの前哨戦として各種API仕様記述フォーマットについて概要を述べておく - Qiita
API Query Language (2016-)
GraphQL が爆誕します。
GraphQL は今までの流れでも解決できていない、「そもそも REST は本質的に難しくて 徹底できない。RESTish が限界」ということを認めて、別のアプローチを取ります。
もちろんデメリットもあります。
詳しくは第 4 部 The NEXT of REST で。
前後リンク
- RESTful API のおさらい
- Rails での JSON API 実装まとめ
- スキーマファースト開発
- The NEXT of REST