Skip to content

3.3 データの内部構造の考え方

3.3 データの内部構造の考え方

まず考えるべきは、API のアクセス回数がなるべく減るようにすること。ユースケースを考える必要がある。
(ユーザー一覧の結果で ID だけ返す => 利用する側はユーザー情報も欲しいはず => 一緒にユーザー情報も返したほうが利用しやすい)

3.3.1 レスポンスの内容をユーザーが選べるようにする

多数の外部ユーザーが利用するような API はすべてユースケースを想定することはできない。
シンプルな解決法はできる限り多くのデータを返す。
ただこの方法ではデータ量が必要以上に大きくなりすぎる。
クエリパラメータで取得したい項目をユーザー側が自由に選択できるようにする
(http://api.example.com/v1/users/123?fields=name,age)

3.3.2 エンベロープは必要か

エンベロープ

{
    "header": {
        "status": "success",
        "errorCode": 0,
    },
    "response": {
        ...実際のデータ...
    }
}

上記のように返却するデータに共通したメタデータを含んだ構造のことをエンベロープと呼ぶ。

冗長な表現のため基本期にはやるべきではない
HTTP のレスポンスヘッダで同様のことができる。むしろ HTTP の知識さえあればメタ情報やエラー情報の意味を理解しやすいため、ユーザーフレンドリーになる。
ただしJSONPでは利用したほうが便利になる。

3.3.3 データはフラットにすべきか

返却するデータを階層的に表すか、フラットに形で表すかは状況次第。

階層
{
    "id": 123,
    "sender": {
        "id": 456,
        "name": "Taro Ymamoto"
    },
    "receiver": {
        "id": 789,
        "name": "Kenji Kato"
    }
}

フラット
{
    "id": 123,
    "sender_id": 456,
    "sender_name": "Taro Yamamot",
    "receiver_id": 789,
    "receiver_name": "Kenji Kato"
}

上記の例では senderreceiver は同じユーザーという構造を表すため階層構造で表現したほうが、利用者側はユーザー型として扱いやすくなる。

{
    "id": 123,
    "name": "Tanaka Taro",
    "profile": {
        "birthday": "193848754",
        "gender": "male",
        "languages": ["ja", "en"]
    }
}

上記の profile 項目のように単にまとめるだけの階層構造はあまり意味がない。フラットに表現したほうがデータサイズが小さくなる。また profile 単体で処理を行うことは考えにくいため、前出のユーザーの場合のように利用者側の利便性もよくならない。

3.3.4 配列とフォーマット

{
    "friends": [
        {
            "id": 123,
            ...
        },
        {
            "id": 345,
            ...
        }
    ]
}

友人一覧等の配列で値を返す場合、以下の理由からそのまま配列を返すよりもレスポンス全体をオブジェクトにして返すほうが良い。

  • レスポンスデータが何を指しているかわかりやすい
  • レスポンスデータをオブジェクトに統一できる (クライアント側で共通の前処理が容易になる)
  • セキュリティ上のリスクを避けることができる

トップレベルが配列である JSON は「JSONインジェクション」という脆弱性に対するリスクがあるため、基本的には API のレスポンスとしてオブジェクトを返すようにするべき。

3.3.5 配列の件数、あるいは続きがあるかをどう返すべきか

全体の件数を把握したうえで現在取得済の件数を考えれば続きがあるかはわかる。
ただし、全体の件数を取得する処理はコストが大きいことが多いので、実際に取得するどうかはユースケースを考える必要がある。
全体の件数が必要ないなら、サーバー側では取得件数 +1 件の取得を試みて、実際に取得件数 +1 件取得できれば、続きがあるとして考えることができる。

続きがあることの返し方は 2 つ

  • 「hasNext」といった名前で結果に含める
  • 次のデータ取得に必要な「パラメータ」や「URL」を結果に含める