テックブログ

APIレスポンス設計入門:フロントが困らないJSONの返し方

APIレスポンス設計入門:フロントが困らないJSONの返し方

APIレスポンス設計は、サーバーが返すJSONの形を、クライアントが扱いやすい“契約”として整えることです。成功時のデータ構造、エラー時に返す情報、空データの表現、ページング、日付や数値の形式をそろえることで、フロントエンドの分岐や例外処理が減り、実装と保守が安定しやすくなります。APIは「値を返せばよい」ではなく、「毎回同じ考え方で受け取れる」ことが大切です。

1. APIレスポンス設計とは

1-1. JSONの形はクライアントとの契約

APIレスポンス設計で一番大事なのは、JSONの形がクライアントとの契約になることです。サーバー側が自由に返してよいデータではなく、受け取る側がその形を前提に実装するものだと考える必要があります。

フロントエンドは、返ってくるJSONのキー名、配列かオブジェクトか、nullが来るのか、エラー時に何が入るのかを前提に画面を作ります。そのため、同じ意味のAPIなのに返し方が毎回違うと、クライアント側で特別対応が増えていきます。つまり、レスポンス形式は「見た目」ではなく、利用側のコード量や保守性に直結する設計要素です。

たとえば、あるAPIでは user.name で取れるのに、別のAPIでは data.user_name になっていると、フロント側は毎回読み替えが必要です。API設計では「返せるか」より、「同じルールで受け取れるか」を優先すると、後から困りにくくなります。

1-2. 場当たり的なレスポンスが保守を難しくする理由

場当たり的なレスポンス設計は、最初は速く作れても、後から修正しづらくなります。特に画面やクライアントが増えるほど、その影響は大きくなります。

開発初期は「今の画面で使えればよい」と考えがちですが、同じAPIを別画面やモバイルアプリ、管理画面などから使うことがあります。そのとき、レスポンスの形が一貫していないと、利用側で毎回変換処理や例外分岐を書くことになります。結果として、API側の少しの変更が複数クライアントの不具合につながりやすくなります。

よくあるのは、一覧APIでは items、別の一覧APIでは list、エラーではあるときだけ message が入る、といったズレです。こうした小さな不統一が積み重なると、フロント側は「どのAPIがどの形だったか」を毎回思い出す必要があり、開発速度が落ちます。

1-3. 成功・失敗・一覧で考える基本

APIレスポンス設計は、まず成功、失敗、一覧の3パターンで考えると整理しやすくなります。最初から全部のケースを細かく考えるより、この3つをそろえるほうが効果的です。

成功時はどんなデータ構造を返すか、失敗時は何を伝えるか、一覧では配列だけでなく件数やページ情報をどう返すか、という基本を決めておくと、API全体のルールが見えやすくなります。逆に、ここを決めないまま実装すると、画面ごとに都合のよい形が増えてばらばらになりやすいです。

最初の設計段階では、「単一データ」「一覧データ」「エラー」の3種類について、同じ考え方で返せるかを確認するとよいです。これだけでも、フロント側の扱いやすさがかなり変わります。

2. 成功レスポンスの設計

2-1. 単一リソースを返す形

単一リソースを返すときは、1件のデータが分かりやすく取れる形にするのが基本です。利用側が余計な深掘りをしなくて済む構造のほうが扱いやすいです。

たとえば、ユーザー詳細APIなら、ユーザー1件の情報がオブジェクトとして返る形が自然です。ここで無駄にネストが深かったり、画面都合で名前が毎回変わったりすると、クライアント側のコードが読みにくくなります。単一リソースでは、「必要な情報がまとまっていること」と「キー名が他APIと整っていること」が大事です。

{
  "id": 1,
  "name": "山田 太郎",
  "email": "taro@example.com",
  "createdAt": "2025-05-20T10:30:00Z"
}

この例では、ユーザー1件の情報をそのまま返しています。注意点は、同じ意味の項目名をAPIごとに変えないことです。たとえばあるAPIで created_at、別のAPIで createdAt と混ざると、フロント側で変換が必要になりやすいです。

2-2. 一覧データを返す形

一覧データを返すときは、配列だけでなく、一覧として必要な補助情報も考えることが大切です。特にページングがある場合は、配列だけ返すと後で困りやすくなります。

一覧APIでは、実際のデータ配列に加えて、総件数、現在ページ、1ページあたりの件数、次ページがあるかなどの情報が必要になることがあります。フロント側は単に配列を並べるだけでなく、「次へ」ボタンや件数表示を出したいからです。つまり、一覧レスポンスはデータ本体と、一覧表示を助ける情報のセットで考えると自然です。

{
  "items": [
    { "id": 1, "name": "商品A" },
    { "id": 2, "name": "商品B" }
  ],
  "total": 25,
  "page": 1,
  "perPage": 10
}

この例では、items に配列を入れ、一覧用の補助情報も返しています。注意点は、一覧APIごとに itemsresultsdata のように名前を変えないことです。一覧系の返し方をそろえるだけでも、フロント側の共通処理が作りやすくなります。

2-3. dataで包むか、そのまま返すか

レスポンスを data で包むか、そのまま返すかは、どちらでもよいですが、ルールをそろえることが重要です。大切なのは“正解の形式”より“全体の一貫性”です。

data で包む形には、成功レスポンスとエラーレスポンスの構造をそろえやすい利点があります。一方で、単純なAPIでは1段ネストが増えるだけとも言えます。つまり、使いやすさはチームやAPI群の考え方によって変わるので、どちらかを選んだら揃えることのほうが大事です。

{
  "data": {
    "id": 1,
    "name": "山田 太郎"
  }
}

このように包むと、将来メタ情報を追加しやすいです。注意点は、あるAPIは data で包み、別のAPIは生のオブジェクトを返す、と混在させないことです。フロント側ではアクセス方法が変わるため、統一されていないと余計な分岐が増えます。

3. エラーレスポンスの設計

3-1. ユーザー向けメッセージと開発者向け情報を分ける

エラーレスポンスでは、ユーザーに見せるための情報と、開発者が調査するための情報を分けることが大切です。これを混ぜると、分かりにくさと危険の両方が出やすくなります。

ユーザーに必要なのは、「何が起きたか」「どうすればよいか」が分かるメッセージです。一方、開発者には、エラーコードや詳細な原因が役立ちます。ただし、内部例外のメッセージやSQLエラーをそのまま返すと、利用者には意味がなく、内部情報を出しすぎる危険もあります。つまり、1つのエラーでも、見る相手に合わせて情報の粒度を考える必要があります。

{
  "errorCode": "USER_NOT_FOUND",
  "message": "指定したユーザーが見つかりません。"
}

この例では、フロントが画面表示しやすいメッセージと、分岐に使いやすいエラーコードを分けています。注意点は、message に内部エラーの詳細をそのまま入れないことです。必要ならサーバーログ側に詳しい情報を残し、レスポンス側は利用者向けに整えるほうが安全です。

3-2. errorCodeを持たせる意味

エラーレスポンスに errorCode を持たせると、フロント側が文字列メッセージに依存せず処理を分けやすくなります。これは見た目よりかなり実務的な利点です。

たとえば、同じ「失敗しました」という画面文言でも、未ログインと在庫切れではフロント側の対応が違います。エラーコードがあれば、ログイン画面へ飛ばす、再入力を促す、モーダルを出す、といった分岐がしやすくなります。メッセージだけで分岐しようとすると、文言変更で画面ロジックが壊れやすくなります。

実務では、USER_NOT_FOUNDVALIDATION_ERROROUT_OF_STOCK のように、意味が分かるコードを定義しておくと扱いやすいです。ポイントは、ユーザー向け文章を条件分岐のキーにしないことです。

3-3. バリデーションエラーの返し方

バリデーションエラーでは、どの項目が、どんな理由で不正かを分かる形で返すのが基本です。これができると、フロント側で入力欄へエラーを対応づけやすくなります。

たとえば、メールアドレスとパスワードの両方に問題があるとき、「入力が不正です」だけでは直しにくいです。項目ごとにエラーを返せば、フロント側で各入力欄の近くへ表示できます。つまり、バリデーションエラーは1件の文章より、「どのフィールドに問題があるか」の情報が重要です。

{
  "errorCode": "VALIDATION_ERROR",
  "message": "入力内容に誤りがあります。",
  "fields": {
    "email": "メールアドレスの形式が正しくありません。",
    "password": "8文字以上で入力してください。"
  }
}

この形にしておくと、フロント側でフォーム項目とひも付けやすくなります。注意点は、APIごとに fields の形式を変えないことです。あるAPIは配列、別のAPIは文字列マップ、という形だと、画面側のエラーハンドリングが複雑になります。

4. 空データとnullの扱い

4-1. 空配列とnullの違い

空データを返すときは、「データがない」の意味を空配列とnullで使い分けることが大切です。この違いが曖昧だと、フロント側の分岐が増えます。

一般的には、「一覧として存在するが中身が0件」は空配列 [] が自然です。一方で、「そもそも値が存在しない」「未設定である」は null が候補になります。つまり、空配列は“空の箱”、nullは“箱自体がない”に近い意味として考えると整理しやすいです。

{
  "items": []
}

一覧APIで0件なら、このように空配列で返すほうがフロントは扱いやすいです。注意点は、同じ一覧APIであるときは []、別のときは null を返さないことです。フロント側で毎回 if (items && items.length) のような余計な分岐が増えます。

4-2. 省略とnullを混ぜない

レスポンス設計では、「キーがない」と「キーはあるがnull」を混ぜないことが大切です。意味がぶれると、利用側が判断しづらくなります。

たとえば、あるユーザーでは nickname キー自体がなく、別のユーザーでは "nickname": null となっていると、フロント側は「省略なのか、未設定なのか、APIの出し忘れなのか」を考えなければなりません。これは実装だけでなく、バグ調査も難しくします。レスポンス形式は、“あるときだけ出す”より、“出すなら出すで意味をそろえる”ほうが扱いやすいです。

もし未設定を表したいなら、null と決めて毎回返すほうが分かりやすいことが多いです。逆に、本当に返さない設計にするなら、そのルールを統一する必要があります。大事なのは、APIごとに気分で変えないことです。

4-3. フロント側の分岐を減らす設計

よいAPIレスポンス設計は、フロント側の分岐を減らせる形になっています。クライアントが毎回「あるかないか」「配列かnullか」を悩まなくて済むほど、実装は安定します。

たとえば、一覧は必ず配列で返す、エラーは必ず同じキー構造で返す、日付は必ず同じ形式で返す、といったルールがあると、フロント側で共通処理を作りやすくなります。逆に、同じようなAPIなのに返し方が微妙に違うと、画面ごとに特別対応が増えていきます。これは後からじわじわ効いてくる保守コストです。

設計時には、「このJSONを受け取る側が、できるだけ同じ書き方で扱えるか」を考えると判断しやすいです。フロントが困らないAPIは、特別扱いが少ないAPIとも言えます。

5. 日付と数値の返し方

5-1. 日付形式を統一する

日付は、API全体で同じ形式に統一するのが基本です。ここがぶれると、画面側で変換ロジックが増えやすくなります。

たとえば、あるAPIでは 2025-05-27T10:30:00Z、別のAPIでは 2025/05/27 19:30 のように混ざると、フロント側は毎回別処理が必要です。APIレスポンスでは、表示しやすい形よりも、機械的に扱いやすく、意味がぶれにくい形式を優先するほうが安定します。一般的にはISO 8601形式がよく使われます。

{
  "createdAt": "2025-05-27T10:30:00Z"
}

このように統一すると、クライアント側で一貫してパースしやすくなります。注意点は、APIが画面向けの表示形式まで返し始めることです。たとえば「2025年5月27日 19時30分」のような表示文言は、通常はフロント側で整形するほうが役割分担として自然です。

5-2. 金額や小数の扱いに注意する

数値、とくに金額や小数は、見た目より“意味の正確さ”を優先して返す必要があります。ここを曖昧にすると、表示や計算でズレが出やすくなります。

たとえば金額を文字列で返すのか、整数の最小単位で返すのか、小数で返すのかは、最初に方針を決めたほうが安全です。JavaScriptでは小数計算で誤差が出ることがあるため、通貨のように厳密さが大事な値は、円なら整数、または最小単位の整数で扱う設計がよく使われます。つまり、「人に見やすい表現」と「計算しやすい表現」は別で考える必要があります。

たとえば1000円を 1000 と返すのか、"1,000円" と返すのかでは用途が違います。後者は表示には便利でも、計算には向きません。APIレスポンスでは、まずデータとして正しく扱える形を返すほうが基本です。

5-3. 表示用文字列とデータ値を分ける

APIレスポンスでは、表示用文字列と元データの値をできるだけ分けるのが扱いやすいです。見た目の都合をそのままデータに混ぜると、再利用しづらくなります。

たとえば金額を "1,200円" だけで返すと、一覧画面では表示できても、合計計算や並び替えで困ります。日付も同じで、見た目用の「2025年5月27日」だけだと、別言語や別画面で使いづらくなります。APIは、画面表示そのものより、クライアントが再利用しやすい元データを返すほうが自然です。

{
  "price": 1200,
  "currency": "JPY",
  "createdAt": "2025-05-27T10:30:00Z"
}

このように返しておけば、フロント側で用途に応じた表示へ変換できます。注意点は、API側が表示専用文字列だけを返してしまうことです。特に将来モバイルアプリや別画面でも使うなら、まず元データを安定して返せるほうが長持ちします。

6. まとめ

6-1. APIレスポンス設計の基本チェックリスト

APIレスポンス設計では、クライアントが毎回同じ考え方で受け取れることが大切です。派手なテクニックより、基本をそろえるほうが実務では効きます。

  • 成功時のJSON構造はAPI間で一貫しているか
  • 一覧レスポンスで配列と補助情報の返し方がそろっているか
  • エラーレスポンスに message と errorCode の役割分担があるか
  • バリデーションエラーで項目ごとの情報を返せるか
  • 空配列、null、省略の意味が混ざっていないか
  • 日付形式が統一されているか
  • 表示用文字列と元データ値を混ぜていないか

このチェックリストを意識するだけでも、「画面ごとに都合のよい返し方」が減りやすくなります。APIはサーバーだけの都合で作るものではなく、受け取る側の保守性まで含めた契約だと考えるのが基本です。

6-2. フロントが困らないための判断基準

フロントが困らないAPIレスポンスかどうかを考えるときは、分岐が少なく、予測しやすく、再利用しやすいかを基準にすると判断しやすいです。これがレスポンス設計の実務的な見方です。

たとえば、同じ種類のAPIなら同じキー構造で受け取れるか、空のときも同じ型で処理できるか、エラー時に画面側が迷わず分岐できるか、という観点です。逆に、毎回特別扱いが必要なら、そのAPIレスポンスは扱いづらい可能性があります。フロントが困るのは、データ量が多いときよりも、ルールが読めないときです。

レスポンス設計で迷ったら、「このJSONを初見のフロント担当が見て、迷わず使えるか」を想像してみるとよいです。APIは返すことが目的ではなく、使われ続けることが目的なので、その視点があると設計の質が上がりやすくなります。

7. 参考リンク