

APIレスポンスのルートは配列じゃなくオブジェクトにする
この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。
APIのJSONレスポンス、ルートをいきなり配列で返すのは避けたほうがいい。
[ { "id": 1, "name": "example" }, { "id": 2, "name": "example" }]これをやると、あとからページング情報や件数、エラー情報を足したくなったときに構造を壊すしかなくなる。なのでルートはオブジェクトにして、中に data を持たせるのが定番。
{ "data": [ { "id": 1, "name": "example" }, { "id": 2, "name": "example" } ], "meta": { "page": 1, "perPage": 10, "total": 100 }}エラー時も同じ形でラップできる。
{ "error": { "code": 400, "message": "Invalid request parameters" }}セキュリティ理由は今はもう主目的じゃない
このパターン、「JSONハイジャック対策」という文脈で語られることが多い。2007年頃、Array コンストラクタを書き換えてルート配列JSONの中身を盗み見る攻撃が実際にあって、Gmailなどが影響を受けたらしい。ただこの攻撃は当時のブラウザ(Firefox 2.0以下など)に限った話で、その後すべてのブラウザで修正済みとのこと。実機で再現できるかは未確認。
なので今この構成を採用する理由としては、セキュリティよりも「拡張性」の比重のほうが大きい。ルートをオブジェクトにしておけば、meta や error を後付けできる。ルートが配列だとそれができない。ここが実務上の本題。
リストが複数あるときはdata配下でキーを分ける
1つのレスポンスに複数のリストを含めたい場合は、data の下にキーごとに分けるのが素直。
{ "data": { "users": [ { "id": 1, "name": "example" } ], "posts": [ { "id": 101, "title": "example" } ] }, "meta": { "usersCount": 1, "postsCount": 1 }}users と posts を混ぜて1つの配列にしないことで、クライアント側がどのリストが何を表すか型で判断できる。メタ情報もリストごとに持たせやすい。
ただしこの構造に唯一の正解があるわけではない。JSON:APIのように data キーを規約として定めている仕様もあるが、大半はチームやプロジェクトの慣習として採用されているだけ。守るべきは「ルートをオブジェクトにして、拡張の余地を残す」という考え方の部分で、キーの命名やネストの深さは案件ごとに決めればいい。