Web APIにはJSONベースのフォーマットを使おう

  • 935
    Like
  • 2
    Comment
More than 1 year has passed since last update.

Web APIを作るとき、JSONのデータ構造をどうするか悩んだことはありますか?

{
  "id": 3342124,
  "message": "Hi!",
  "user": {
    "id": 3456,
    "name": "Taro Yamada",
    "image_url": "/images/taro.png"
  }
}

フラットにする

{
  "id": 3342124,
  "message": "Hi!",
  "user_id": 3456,
  "user_name": "Taro Yamada",
  "user_image_url": "/images/taro.png"
}

エンベロープでデータ全体を包む

{
  "response": {
    "id": 3342124,
    "message": "Hi!",
    "user": {
      "id": 3456,
      "name": "Taro Yamada",
      "image_url": "/images/taro.png"
    }
  }
}

など、どの構造がいいでしょうか? もっと違う構造も考えられます。

JSONはシンプルですが、構造に制約がなさすぎます。適切な設計を行うには適切な制約が必要です。

そこで、plain JSONに少し制約を加えたJSONベースのフォーマットを使うことをおすすめします。

もしあなたが、JSONレスポンスをどのようなフォーマットにするかをチームで議論したことがあるなら、JSON APIは『自転車置き場の議論』に対抗する武器となる。
共有された規約に従うことで、生産性が向上し、汎用的なツールを利用でき、アプリケーションという重要なものに集中することができる。

http://jsonapi.org/ より

制約の弱いもの、強いもの、さまざまなフォーマットが存在しますが、今回は比較的制約の強いフォーマットを紹介します。

HAL

http://stateless.co/hal_specification.html

Content-Type: application/hal+json

{
  "_links": {
    "self": { "href": "/messages/3342124" }
  },
  "id": 3342124,
  "message": "Hi!",
  "_embedded": {
    "user": {
      "_links": {
        "self": { "href": "/users/3456" }
      },
      "id": 3456,
      "name": "Taro Yamada",
      "image_url": "/images/taro.png"
    }
  }
}

通常のオブジェクト(リソースと呼ぶ)に _links _embedded というプロパティを加えたものになっています。この _embedded の中にさらにリソースを入れられる(埋め込みリソース)ようになっているので、ただネストするよりも、複数のリソース間の関係がはっきりします。

HALのデータモデル
図:HALのデータモデル

HALは現在インターネットドラフトになっています。また、最近AWSのAPIでは積極的にHALが採用されています。

例: http://docs.aws.amazon.com/apigateway/api-reference/

JSON API

http://jsonapi.org/

Content-Type: application/vnd.api+json

紛らわしいですが、“JSON API”というフォーマットの名前です。

{
  "links": {
    "self": "/messages/3342124"
  },
  "data": {
    "type": "messages",
    "id": 3342124,
    "attributes": {
      "message": "Hi!"
    },
    "relationships": {
      "user": {
        "data": {
          "type": "users",
          "id": 3456
        }
      }
    }
  },
  "included": [{
    "links": {
      "self": { "href": "/users/3456" }
    },
    "type": "users",
    "id": 3456,
    "attributes": {
      "name": "Taro Yamada",
      "image_url": "/images/taro.png"
    }
  }]
}

JSON APIでは、従来のデータ(キー・値)は data の中の attributes に入ります。それに加えて、リソースを識別するために typeid を使用します。

リソース間の関係を記述するため、特別に relationships が用意されています。また、埋め込みリソースは included で可能です。

さらに、JSON APIの特徴として、以下のようにかなり仕様が豊富です。

  • GETだけではなく、POST/PATCH/DELETE(いわゆるCRUD操作)の仕様を定義している
  • 特定のフィールドのみを指定したり、コレクションのsort、page、filterを行うURLパラメータの仕様を定義している
  • エラー時のフォーマットを定義している

Collection+JSON

http://amundsen.com/media-types/collection/

Content-Type: application/vnd.collection+json

{
  "collection": {
    "version": "1.0",
    "href": "/messages",
    "items": [{
      "href": "/messages/3342124",
      "data": [
        { "name": "id", "value": 3342124 },
        { "name": "message", "value": "Hi!" }
      ],
      "links": [
        { "rel": "user", "href": "/users/3456" }
      ]
    }],
    "template": [{
      "data": [
        { "name": "message", "value": "", "prompt": "Enter message" }
      ]
    }],
    "queries": [{
      "rel": "search",
      "href": "/messages/search",
      "prompt": "Search messages",
      "data": [
        { "name": "q", "value": "" }
      ]
    }]
  }
}

Collection+JSONは基本的にコレクション(複数のリソースをまとめたもの)を扱うフォーマットです。データは collection の中の items に配列として入ります。配列の中身を1つだけにすることで単独のリソースも表すことができます。

埋め込みリソースは標準では用意されていません(拡張仕様で可能)。

Collection+JSONの一番の特徴は template queries です。これはHTMLのフォームのようにリクエスト時のパラメータを指定します。 template はリソースに対するPOST/PUT/DELETE操作のとき、 queries はそれ以外の検索などの操作に使用します。クライアントはこの記述に従うことでサーバに正しいクエリのリクエストを送信することができます。

また、エラー時のフォーマットも定義されています。

フォーマットを使うメリット

  • データ構造の設計に悩まなくてよくなる
  • クライアント・サーバの実装にそのフォーマット用のライブラリを利用できる
  • フォーマットの仕様がデータ構造(場合によってリクエストパラメータなども)の仕様になるので、その部分についてはドキュメントを書く必要がなくなる

うまくライブラリを使えば、作業が大幅に省力化できるでしょう。

JSONベースのフォーマット自体がまだマイナーなので、必要なプラットフォームのライブラリがまだないかもしれませんが、汎用的な仕様なので、一度ライブラリを書けば以後も再利用することができます。

今回紹介したものはWeb APIのための汎用的なフォーマットなので、Web APIに特化したさまざまな仕様が用意されています。ぜひ採用を検討してみてはいかがでしょうか。


参考:ライブラリのリンク集

This post is the No.5 article of Web API Advent Calendar 2015