Help us understand the problem. What is going on with this article?

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

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


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

sonicgarden
「お客様に無駄遣いをさせない受託開発」と「習慣を変えるソフトウェアのサービス」に取り組んでいるソフトウェア企業
http://www.sonicgarden.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした