Rails
WebAPI
api
rest

HTMLでWeb APIをつくる

More than 3 years have passed since last update.

シングルページアプリケーションやモバイルアプリなどの普及により、サーバサイドではJSONを出力するWeb APIの必要性が高くなってきています。みなさんはどのようにWeb APIを作っているでしょうか。

JSONはビュー

http://qiita.com/yuch_i/items/f6b04e2875f432f8f806

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→JSON変換というアイデアは、以前から存在していて、新しいというわけではありません。

その他のJSON変換仕様の例:

俺俺フォーマットのJSONが濫造される中、なんとか簡単に統一的なフォーマットのJSONを作る方法はないか、と考えた結果、これにたどりつきました。

これからAPIを作るときには、HTMLを書くというのはどうでしょうか?

試作中

このアイデアが実現できるように、Railsで自動的に変換してJSON(HAL, UBER)レスポンスを返すgemを現在試作しています。