rest

RESTful API設計におけるHTTPステータスコードの指針

More than 1 year has passed since last update.

RESTful APIを設計した際のステータスコードの指針です。

メソッド別

GET

成功した場合

  • 200 OK:最も一般的
  • 304 Not Modified:条件付きGETでキャッシュを使わせたい場合

POST

成功した場合

  • 201 Created
    • 作成したリソースのURIを示すLocationヘッダを付けておく

議論

  • 200 OKだとまずいのか?
    • 200 OKを応答する実装も多くあり、まずいというわけでもない
    • 200 OKはPOST結果がキャッシュ可能、201 CreatedはPOST結果がキャッシュ不可能として分けてもいいが、そこまでする必要があるか?(POSTのキャッシュは一般的ではない)
  • 204 No Contentだとまずいのか?
    • クライアントがPOST結果を事前に全て知っているわけではないのでNo Contentは不親切では?

失敗した場合

  • 409 Conflict:作成しようとしたリソースが既にある場合

成功でも失敗でもない場合

  • 303 See Other:作成しようとしたリソースが既にあるが失敗とみなさないようにする場合
    • 既存の同一とみなすリソースのURIを示すLocationヘッダを付けておく
    • ただし、失敗とみなすのが普通かもしれない

PUT

成功した場合

  • 204 No Content:更新の場合
  • 201 Created:新規作成の場合
    • 作成したリソースのURIを示すLocationヘッダを付けておく

議論

  • PUTで新規作成できるAPIを提供する必要があるかどうかはまた別の話
  • 更新の場合200 OKだとまずいのか?
    • まずくはないが、PUTが成功したということはクライアントにとって自分の思い通りの結果になったということなので中身はそんなに重要ではない。204 No Contentで十分。

失敗した場合

  • 409 Conflict:作成しようとしたリソースが既にある、または、更新しようとしたリソースがロック中(楽観・悲観どちらでも)の場合

PATCH

成功した場合

  • 200 OK:パッチしたリソースを返却する場合
  • 204 No Content:パッチしたリソースを返却しない場合

失敗した場合

  • 409 Conflict:パッチしようとしたリソースがロック中(楽観・悲観どちらでも)の場合

DELETE

成功した場合

  • 204 No Content

失敗した場合

  • 409 Conflict:削除しようとしたリソースがロック中(悲観)の場合

議論

  • 削除しようとしたリソースがRDBでいうところの参照整合性制約違反のため削除できない場合
    • そのリソースを削除しようとすること自体が間違いなのでサーバエラーではなくクライアントエラーであるはず
    • 422 Unprocessable Entityもしくは409 Conflict
  • 削除済みの場合、410 Goneを使うべきか?
    • 不要。404 Not Foundで十分。
    • ただし、最初から存在しないリソースを削除しようとした時と区別がつかない

どんなメソッドでも

成功した場合

  • 205 Reset Content:不要。リセットするかどうかはクライアントが考えればよいのでは?

失敗した場合

  • 4xxは通知することでクライアントまたはユーザが反応できる可能性があるときに応答する
    • 400 Bad Request:データ形式が間違っている場合(JSONのパースエラーなど)
    • 401 Unauthorized:何らかの認証が必要な場合。言い換えるとAuthorizationヘッダが必要な場合。
    • 402 Payment Required:支払いが必要な場合。(RFCでは将来のための予約らしいがWebPayがこれで応答する時がある)
    • 403 Forbidden:不要。クライアントが403を受け取っても特別な意味のある処理はできないのなら404 Not Foundで十分。
    • 404 Not Found:存在しない場合。または、存在することを隠したい場合。
    • 405 Method Not Allowed:そのリソースに指定されたメソッドが用意されていない場合。
    • 406 Not AcceptableAcceptヘッダとマッチしない場合。
    • 408 Request Timeout:不要。そもそも、これがクライアントエラーであることをサーバ側ではどうやって判定するのだろう。
    • 415 Unsupported Media Type:データ形式は正しいがサーバが相手にしたくない場合。
  • 5xxは通知しても反応に困るときに応答する
    • 500 Internal Server Error:その他のサーバに起因するエラーにより処理続行できない場合。
    • 503 Service Unavailable:一時的にサービス提供ができない場合。(メンテナンス等)

議論

  • 入力チェックエラーについて
    • データ形式が間違っている場合は400 Bad Request
    • データ形式は間違っていなくてもサーバ側で処理できない場合は415 Unsupported Media Type
    • データ形式は間違っていなくて処理もできるがビジネスロジック上受け入れてはいけない場合は422 Unprocessable Entity
    • 422 Unprocessable EntityはWebDAV拡張だけど使っていいのか?(Railsがデフォルトで使っている)
  • 存在しないものについて
    • URIで表されたリソースが存在しない場合404 Not Foundとする
    • URIで表されていないが処理継続に必要になるリソースが存在しない場合はどうするか
      • 場合によっては500 Internal Server Errorかもしれない
    • POSTの場合は処理対象とするリソースそのものはなくても構わない
      • 例えば、/posts/1/commentscommentsはなくてもいいが/posts/1がないと404 Not Found
  • 外部システムのエラーについて
    • サーバが別のシステムに依存していて、そのシステムがエラーを返した場合
      • 別システムが起因(5xx)の場合、その別システムが正常に動くようになるまで503 Service Unavailable
      • 自サーバが起因(4xx)の場合
        • クライアントから与えられたデータを丸投げしているだけの場合、422 Unprocessable Entity
        • サーバ内で何らかの処理をしている場合、500 Internal Server Error
  • エラー詳細について
    • エラーの場合は、結局レスポンスボディになんらかのエラー詳細情報を含めないとクライアント側では反応に困ることになる
    • ということは、実際問題としてステータスコードでは400500だけ分けておいて、細かいことはエラー詳細情報で判断するようにしてもいいのでは?