はじめに
Day11 では
✅ HTTPステータスコードを正しく返す設計
を学びました。
今日はその続きとして、
✅ 「JSONレスポンスの中身をどう設計するのが正解なのか?」
を徹底的に解説します。
正直に言います。
❌ JSONレスポンスの設計がグチャグチャな API は
❌ フロントエンド開発が地獄になります。
今日でそれを完全に終わらせます。
今日のゴール
・成功・失敗で JSON を統一できるようになる
・一覧・詳細・作成・更新のレスポンス形式を揃えられる
・フロントエンドが「考えなくても」扱える API になる
・実務レベルのレスポンス設計ができるようになる
なぜ JSON レスポンス設計が重要なのか?
例えば、こんなレスポンスが混在していたらどうでしょう?
{ "result": "ok", "post": {...} }
{ "success": true, "data": {...} }
{ "status": "error", "msg": "失敗しました" }
フロント側は毎回こうなります。
if (res.result) { ... }
if (res.success) { ... }
if (res.status === 'error') { ... }
✅ 分岐地獄
✅ バグの温床
だからこそ JSON の形式は「全APIで統一」する必要があります。
結論:これが最強の JSON レスポンス設計
まずは これを全APIで固定してください。
成功時の基本フォーマット
{
"status": "success",
"data": {...}
}
失敗時の基本フォーマット
{
"status": "error",
"message": "エラーメッセージ"
}
たったこれだけです。
✅ これだけで フロント側が超書きやすくなります。
一覧取得(GET /posts)のレスポンス設計
{
"status": "success",
"data": [
{ "id": 1, "title": "最初の投稿" },
{ "id": 2, "title": "2つ目の投稿" }
]
}
✅ 配列は必ず data に入れる
✅ ページネーションも data を崩さずに追加できる
詳細取得(GET /posts/1)
{
"status": "success",
"data": {
"id": 1,
"title": "最初の投稿",
"body": "本文です"
}
}
✅ 一件でも必ず data に入れる
✅ 一覧と 構造を揃える
新規作成(POST /posts)
{
"status": "success",
"message": "投稿を作成しました",
"data": {
"id": 3,
"title": "新しい投稿"
}
}
✅ ユーザー向け文言 → message
✅ データ → data
更新(PUT /posts/1)
{
"status": "success",
"message": "投稿を更新しました",
"data": {
"id": 1,
"title": "更新後タイトル"
}
}
✅ 作成も更新も 構造は同じ
削除(DELETE /posts/1)
{
"status": "success",
"message": "投稿を削除しました"
}
✅ 削除後は data を返さなくてもOK
バリデーションエラー(400)
{
"status": "error",
"message": "タイトルは必須です"
}
認証エラー(401)
{
"status": "error",
"message": "ログインが必要です"
}
存在しないデータ(404)
{
"status": "error",
"message": "投稿が見つかりません"
}
サーバエラー(500)
{
"status": "error",
"message": "サーバ側で問題が発生しました"
}
Laravel で JSON フォーマットを統一する実装例
成功レスポンス
return response()->json([
'status' => 'success',
'data' => $post
], 200);
エラーレスポンス
return response()->json([
'status' => 'error',
'message' => '投稿が見つかりません'
], 404);
フロントエンド(React)側はこう書ける
fetch('/api/posts')
.then(res => res.json())
.then(json => {
if (json.status === 'success') {
setPosts(json.data);
} else {
alert(json.message);
}
});
✅ 成功でも失敗でも
✅ 同じ分岐ロジックがすべてのAPIで使い回せます
JSON 設計で初心者が必ずやるミス
APIごとにレスポンス構造が違う
{ "post": {...} }
{ "posts": [...] }
{ "item": {...} }
✅ 全部 data に統一する
エラーメッセージが配列だったり文字列だったりする
{ "message": ["必須です"] }
{ "message": "必須です" }
✅ メッセージの型も必ず揃える
ステータスと JSON の意味がズレている
HTTP 200
{
"status": "error"
}
✅ HTTPステータスと JSON の意味は一致させる
今日のまとめ
・JSONレスポンスは 全APIで統一する
・成功:{ status: "success", data: ... }
・失敗:{ status: "error", message: "..." }
・一覧・詳細・作成・更新はすべて同じ構造でOK
・フロント側は status だけ見ればよくなる
・APIが「チームで使える設計」に進化する
次回 Day13 は…
「ミドルウェアでリクエストを加工する:認証・ログ・バリデーションの入口」
これでいよいよ
✅ 「誰が・いつ・どのリクエストを送ってきたのか」
を制御できるようになります。