Web API のレスポンスについて考える
API のレスポンスの正解って何なの?
API を作るたびにレスポンスはどうすればいいのかしらと迷い。
毎回悩むので自分用にちょっとまとめてみようと思いまして。
注意: この記事は個人の感想なので、ベストプラクティスではありません。
デファクトスタンダードとか、ベストプラクティスとかはあるの?
現在はこれかなというのは次の2点。
RFC 7807 - Problem Details for HTTP APIs
HTTP APIの新しいエラー応答フォーマットを定義する必要をなくすために、HTTP応答でマシンが読み取り可能なエラーの詳細を伝える方法として「問題の詳細」を定義したもの。
問題の詳細のデータモデルはJSONオブジェクトで、「application / problem + json」メディアタイプを使用する。
問題詳細オブジェクトには、次のメンバーを含めることができる。
- "type" (string) - 問題のタイプを識別するURI参照
- "title" (string) - 人間が読める形式の問題タイプの概要
- "status" (number) - この問題の発生に対してオリジンサーバーによって生成されたHTTPステータスコード
- "detail" (string) - この問題の発生に固有の、人間が読める説明
- "instance" (string) - 問題の特定の発生を識別するURI参照
- (拡張メンバー) - 問題固有の追加情報
例) Laravel でこの形式のレスポンスを返す
return response()->json([
'type' => 'https://example.com/probs/out-of-credit',
'title' => 'You do not have enough credit.',
'detail' => 'Your current balance is 30, but that costs 50.',
'instance' => '/account/12345/msgs/abc',
'balance' => 30,
'accounts' => [
'/account/12345',
'/account/67890'
]
], 403, [
'Content-Type' => 'application/problem+json',
'Content-Language' => 'en'
]);
json メソッドの第2引数にステータスコードをセット、第3引数の headers に Content-Type をセットすると 'application/json' より優先(上書き?)される。
"type" は "逆参照すると、問題の種類について人間が読める形式のドキュメントが提供されるようになる" とのことなので、問題一覧みたいなページを作る必要がありそう。そこまでできるかなぁ?ない場合は "about:blank" とみなされるらしい。うーん、なしでもいいですか。
あと、例として挙げられているレスポンスの Content-Language が英語なのだけれど、日本人なわたしが作る日本人しか使わない API は Content-Language: ja にしても許されるのだろうか。だってほら、全部英語は厳しい気がする。
リクエストメソッドごとにレスポンスを考えてみる
GET
GETでリクエストするのはデータの取得。
-
200 OK
レスポンスボディでデータを返す -
404 Not Found
該当データがみつからない例えばこんなかんじ?HTTP/1.1 404 Not Found Content-Type: application/problem+json Content-Language: en { "title": "Resource not found.", "detail": "The requested resource does not exist.", "instance": "/resource/404", }
POST
POSTでリクエストするのはデータの新規登録、もしくはリクエストに含まれるデータを利用した何らかの処理。
- 200 OK
レスポンスボディで処理結果を返す - 201 Created
リクエストは成功し、その結果新たなリソースが作成された場合
レスポンスボディで作成したリソースを返す - 400 Bad Request
必須パラメータが不足しているなど、リクエストが無効な場合 - 409 Conflict
ユニークキーの重複など、何らかの理由でリソースの作成に失敗した場合
PUT | PATCH
PUT | PATCHでリクエストするのはデータの更新。
- 200 OK
レスポンスボディで更新したリソースを返す - 400 Bad Request
必須パラメータが不足しているなど、リクエストが無効な場合 - 404 Not Found
更新対象のリソースが存在しない場合 - 409 Conflict
何らかの理由でリソースの更新に失敗した場合
DELETE
DELETEでリクエストするのはデータの削除。
- 200 OK
レスポンスボディは...IDとか? - 404 Not Found
削除対象のリソースが存在しない場合
(既にないというのを気にしない場合は返さなくてもいいのかも?)
メソッドに関係なく起こりそうなエラー
- 400 Bad Request
構文が無効であるためサーバーがリクエストを理解できない - 401 Unauthorized
認証が必要 - 403 Forbidden
アクセス権がない - 404 Not Found
URLが解釈できない
今回思ったこと
RFC 7807 にきっちり対応するのは厳しそうだけど、
- エラーのときにJSONを返すこと
- 適切なステータスコードを設定すること
- Content-Type は "application/problem+json"
- タイトルと詳細、エラー解決のために必要な情報(値)を含めること
くらいなら実践できるかな。
Discussion