シングルページアプリケーションやモバイルアプリなどの普及により、サーバサイドではJSONを出力するWeb APIの必要性が高くなってきています。みなさんはどのようにWeb APIを作っているでしょうか。
JSONはビュー
RailsでJSON APIを定義する時、素のままでやろうとすると
コントーラでto_jsonを呼んだり、モデルにas_jsonを定義したりすることになるかと思います。モデルに書くとAPIによって出力内容を変えたい場合にとても苦労します。
API数が増えれば増えるほどモデルが複雑になっていきます。APIレスポンスとしてのJSONはコントローラやモデルに書くべきでしょうか?
ビューに書いた方が自然ではないでしょうか?
これはRailsでの話ですが、Railsに限らず、フレームワークを使ってWeb APIを作るときに一般的にあてはまることだと思います。
変化に強い、再利用可能なAPIが必要
モデルをただJSONに変換すると、内部仕様であるモデルの属性名がそのまま露出します。意味はほとんど同じなのに、少しだけ違うAPIができてしまいます。さらに、属性名に依存してクライアントを作ってしまうと、モデルが変更されたときに壊れます。
今のWeb APIはそれぞれバラバラなフォーマットで定義されていて、共通な部分が少なすぎるという印象があります。APIが変わると、いつもゼロからコーディングしなければなりません。
では具体的にどうやって書けばいいでしょう?
リンクは柔軟性を生む
リンクは、あるリソースを別のリソースと結びつけるものです。これにより、Web APIに柔軟性が生まれます。
クライアントを壊さずにAPIを変更するには、モデルの属性名を「変更されないもの=標準の名前」に結びつければいいのです。
さらに、標準の名前に結びつけることで、少しずつ違うAPIが標準化され、再利用することができます。
HTMLをテンプレートとして使う
JSONには、残念ながらリンクがありません。
しかし、リンクを持っていて、さらに標準の名前に結びつけるしくみも持っているフォーマットがあります。HTMLです。
そのしくみの1つとして、microdataがあります。
https://support.google.com/webmasters/answer/176035?hl=ja
<div itemscope itemtype="http://schema.org/Person">
私の名前は<span itemprop="name">東京太郎</span>ですが、
みんなから「<span itemprop="nickname">東太</span>」と呼ばれています。
私のホームページは、
<a href="http://www.example.com" itemprop="url" rel="about">www.example.com</a> です。
<span itemprop="address" itemscope
itemtype="http://schema.org/Address">
<span itemprop="locality">東京都</span>,
<span itemprop="region">港区</span>
</span>
に住んでおり、<span itemprop="title">エンジニア</span>
として <span itemprop="affiliation">ACME 社</span>に勤めています。
</div>
このマークアップで「schema.org」という標準の名前と結びつけることにより、GoogleはこのHTMLをクロールしたときデータとして認識し、検索結果に反映させます。
このHTMLは例えば、このようなJSONとみなすことができます。(これはHALというフォーマットのJSONです)
{
"name":"東京太郎",
"nickname":"東太",
"url":"http://www.example.com",
"title":"エンジニア",
"affiliation":"ACME 社",
"_links":{
"type":{
"href":"http://schema.org/Person"
},
"about":{
"href":"http://www.example.com"
}
},
"_embedded":{
"address":[
{
"locality":"東京都",
"region":"港区",
"_links":{
"type":{
"href":"http://schema.org/Address"
}
}
}
]
}
}
このような形になると、もうWeb APIそのものです。つまり、HTMLはWeb APIとして使えるのです。元のモデルやHTMLが変更されても、microdataのマークアップさえ正しければ、同じJSONとみなすことができます。クライアントは壊れません。
JSONへの変換(もしくはデータの抽出)はサーバサイドでもクライアントサイドでも構いません。
クライアントサイドではmicrodata DOM APIという仕様が定義されていて、JavaScriptによる実装も存在します。
- Microdata-JS https://github.com/termi/Microdata-JS
microdata→JSON変換というアイデアは、以前から存在していて、新しいというわけではありません。
その他のJSON変換仕様の例:
- WHATWG http://www.whatwg.org/specs/web-apps/current-work/multipage/microdata.html#json
- JSON-LD http://www.w3.org/TR/json-ld/#microdata
俺俺フォーマットのJSONが濫造される中、なんとか簡単に統一的なフォーマットのJSONを作る方法はないか、と考えた結果、これにたどりつきました。
これからAPIを作るときには、HTMLを書くというのはどうでしょうか?
試作中
このアイデアが実現できるように、Railsで自動的に変換してJSON(HAL, UBER)レスポンスを返すgemを現在試作しています。