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


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 Acceptable`：`Accept`ヘッダとマッチしない場合。
	- `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/comments`の`comments`はなくてもいいが`/posts/1`がないと`404 Not Found`
- 外部システムのエラーについて
	- サーバが別のシステムに依存していて、そのシステムがエラーを返した場合
		- 別システムが起因(`5xx`)の場合、その別システムが正常に動くようになるまで`503 Service Unavailable`
		- 自サーバが起因(`4xx`)の場合
			- クライアントから与えられたデータを丸投げしているだけの場合、`422 Unprocessable Entity`
			- サーバ内で何らかの処理をしている場合、`500 Internal Server Error`
- エラー詳細について
	- エラーの場合は、結局レスポンスボディになんらかのエラー詳細情報を含めないとクライアント側では反応に困ることになる
	- ということは、実際問題としてステータスコードでは`400`と`500`だけ分けておいて、細かいことはエラー詳細情報で判断するようにしてもいいのでは？