JSON Toolkit

API レスポンスはどんな構造にすべきか

要点:裸のオブジェクトはメタデータが必要になるまで綺麗で、完全なエンベロープは安全だが冗長です。ほとんどのプロジェクトでは結果に HTTP ステータス、データに安定したエンベロープを使います。

中級約 4 分で読めます2026-10-30 公開2026-10-30 更新
三つの API レスポンス形状とそのトレードオフ

要点:結果は 4xx/5xx ステータスコードで表し、ペイロードを { "data": ..., "meta": ... } で運び、失敗時は error エンベロープに切り替えましょう。内部 API にはこれで十分で、多くの統合者を持つ公開プラットフォームだけが JSON:API や OpenAPI を必要とします。

最初に最悪の選択肢を除外します。常に 200 を返し、結果を code フィールドに入れること。

三つの形

A. 裸のオブジェクト

{ "id": 1, "name": "demo", "price": 99 }

綺麗で、HTTP の意味論が仕事をします(404 は 404)。しかしページネーション、警告、トレース ID が必要になった瞬間、契約を変えずに置く場所がありません。

B. 安定したエンベロープ

{
  "data": { "id": 1, "name": "demo" },
  "meta": { "requestId": "abc", "took": 12 }
}

ペイロードとメタデータが分かれて住むので、新しいメタデータが data を再形成しません。コストはネスト一段です。

C. 全部エンベロープ(避ける)

{ "code": 0, "message": "success", "data": {...} }

形が罪ではなく、慣行が罪です。すべての結果に 200 を返すと、CDN、ゲートウェイ、サーキットブレーカー、リトライポリシー、ダッシュボードがすべて成功を見ます。すべてのアラートが独自パースを必要とします。

推奨

結果は HTTP ステータス、ペイロードはエンベロープ。

{
  "data": { "id": 1, "name": "demo" },
  "meta": { "requestId": "req_8f2a", "took": 12 }
}
{
  "error": {
    "code": "ORDER_NOT_FOUND",
    "message": "注文が存在しないか削除されました",
    "details": [{ "field": "id", "issue": "not_found" }]
  },
  "meta": { "requestId": "req_8f2a" }
}

ステータスは 4xx か 5xx。code は安定して機械可読。message は人間向け。details はフィールド単位のフォームエラー用。

厳格な規則

  1. リストエンドポイントはページネーションのメタデータを運ばなければならない。 total かカーソルがなければページャーがありません。
  2. 空のリストは [] を返し、決して null にしない。 null.map は繰り返し起きる障害です。
  3. タイムスタンプはオフセット付き ISO 8601。 タイムスタンプはどの形式かを参照。
  4. 命名規則は一つ。 snake_case か camelCase、境界で一度だけ変換。
  5. 金額は整数の最小単位か文字列。 99.99 は二進浮動小数点では正確でない。
  6. null と欠落を混同しない。 null かフィールド省略かを参照。

仕様を採用すべきとき

  • 多くの統合者を持つ公開プラットフォーム:JSON:API か OpenAPI と共有エンベロープ
  • 単一チームの内部 API:上のエンベロープで十分
  • 強い契約:Schema 優先で、構造はそこから生成

仕様は議論を節約し、オンボーディングのコストを払います。五人チームでは、JSON:API は通常マイナスの仕事です。

FAQ

裸のオブジェクトとエンベロープはどう選べばよいですか?

ページネーション、警告、requestId が必要ならエンベロープを使い、data を再形成せずに meta を育てられるようにします。メタデータが不要で、後からフィールドを足すと契約が変わることを受け入れられるなら、裸のオブジェクトを返します。

API がすべての結果に 200 を返してはならないのはなぜですか?

CDN、ゲートウェイ、サーキットブレーカー、リトライポリシー、ダッシュボードは HTTP ステータスを読んでキャッシュ、リトライ、アラートを決めます。どこでも 200 だと失敗を成功として扱い、すべてのアラートが業務コードの独自パースを必要とします。

リストエンドポイントはページネーションのメタデータを運ぶべきですか?

はい。total かカーソルがなければページャーがなく、空のリストは null ではなく [] を返さなければ、フロントエンドの .map 呼び出しが壊れます。

さらに読む