LoginSignup
1130
1109

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-12-06

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

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

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

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に特化したさまざまな仕様が用意されています。ぜひ採用を検討してみてはいかがでしょうか。


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

1130
1109
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1130
1109