要点
REST APIはHTTPステータスコードを正しく使用すべきです。成功したGETには200、リソース作成を伴う成功したPOSTには201、成功したDELETEには204、クライアントエラーには400、認証失敗には401、見つからない場合は404、サーバーエラーには500を使用します。Modern PetstoreAPIは、適切なセマンティクスとRFC 9457エラー応答で、すべての標準HTTPステータスコードを実装しています。
はじめに
あなたのAPIはすべてに対して200 OKを返します。成功?200 OK。バリデーションエラー?ボディにエラーメッセージを含む200 OK。リソースが見つからない?{"error": "not found"}というメッセージを含む200 OK。認証失敗?ご想像のとおり、200 OKです。
これは間違いです。HTTPステータスコードには理由があります。それらはレスポンスボディを解析することなく、クライアントに何が起こったかを伝えます。キャッシュ、プロキシ、監視ツールはステータスコードに依存しています。エラーに対して200を返すと、HTTPエコシステム全体が壊れます。
古いSwagger Petstoreはステータスコードの間違いを犯していました。201を返す必要があるPOSTリクエストに対して200を返し、204を返す必要があるDELETE操作に200を使用し、重要なエラーコードが欠落していました。Modern PetstoreAPIは、すべてのエンドポイントで適切なHTTPセマンティクスを実装することで、これを修正しています。
このガイドでは、REST APIにとって重要なHTTPステータスコード、それぞれの使用場面、そしてModern PetstoreAPIがそれらをどのように正しく実装しているかを学びます。
ステータスコードの問題
多くのAPIはステータスコードを後回しにしています。その結果、HTTPセマンティクスが壊れ、クライアントが混乱します。
「すべてを200 OKにする」アンチパターン
// 成功
GET /users/123
200 OK
{"id": 123, "name": "John"}
// エラー(しかし200!)
GET /users/999
200 OK
{"error": "User not found"}
// バリデーションエラー(これも200!)
POST /users
200 OK
{"error": "Email is required"}
問題点:
- クライアントはボディを解析せずに成功と失敗を区別できません
- HTTPキャッシュはエラー応答をキャッシュします
- 監視ツールは誤検知を報告します
- 再試行ロジックが正しく機能しません
なぜこれが起こるのか
開発者が200を返す理由:
- 他のステータスコードを知らない
- ステータスコードはオプションだと考えている
- クライアントを「壊す」ことを避けたい
- 悪い例(古いSwagger Petstoreなど)を模倣している
REST APIの重要なHTTPステータスコード
60以上のHTTPステータスコードすべてが必要なわけではありません。これらの重要なものに焦点を当てましょう。
早見表
成功 (2xx):
- 200 OK - 成功したGET、PUT、PATCH
- 201 Created - リソース作成を伴う成功したPOST
- 204 No Content - レスポンスボディのない成功したDELETE、PUT
クライアントエラー (4xx):
- 400 Bad Request - 無効なリクエスト形式またはバリデーションエラー
- 401 Unauthorized - 認証情報がない、または無効
- 403 Forbidden - 認証済みだが許可されていない
- 404 Not Found - リソースが存在しない
- 409 Conflict - リソースの競合(重複、バージョン不一致)
- 422 Unprocessable Entity - 有効な形式だがセマンティックエラー
- 429 Too Many Requests - レート制限超過
サーバーエラー (5xx):
- 500 Internal Server Error - 予期せぬサーバーエラー
- 502 Bad Gateway - アップストリームサービスエラー
- 503 Service Unavailable - 一時的なサービス停止
- 504 Gateway Timeout - アップストリームのタイムアウト
成功コード (2xx)
成功コードはリクエストが成功したことを示します。異なるコードは異なる意味を伝えます。
200 OK
使用場面:データを返す成功したGET、PUT、PATCHリクエスト。
GET /pets/123
200 OK
{
"id": "019b4132-70aa-764f-b315-e2803d882a24",
"name": "Fluffy",
"species": "CAT"
}
使用しない場面:リソースを作成するPOSTリクエスト(201を使用)、DELETEリクエスト(204を使用)。
201 Created
使用場面:新しいリソースを作成する成功したPOSTリクエスト。
POST /pets
201 Created
Location: https://petstoreapi.com/pets/019b4132-70aa-764f-b315-e2803d882a24
{
"id": "019b4132-70aa-764f-b315-e2803d882a24",
"name": "Fluffy",
"species": "CAT"
}
要点:
- 新しいリソースのURLを含む
Locationヘッダーを含める - 作成されたリソースをレスポンスボディで返す
- クライアントはリソースが単に更新されたのではなく、作成されたことを知る
Modern PetstoreAPIは、リソースを作成するすべてのPOST操作に対して201を返します。
204 No Content
使用場面:レスポンスボディのない成功したDELETE、PUT、またはPATCHリクエスト。
DELETE /pets/019b4132-70aa-764f-b315-e2803d882a24
204 No Content
要点:
- レスポンスボディがない(帯域幅を節約)
- 成功を示す
- DELETE操作で一般的
クライアントエラーコード (4xx)
クライアントエラーコードは、クライアントが間違いを犯したことを示します。リクエストは修正なしに再試行すべきではありません。
400 Bad Request
使用場面:不正な形式のリクエスト、無効なJSON、必須フィールドの欠落。
POST /pets
400 Bad Request
Content-Type: application/problem+json
{
"type": "https://petstoreapi.com/errors/validation-error",
"title": "Validation Error",
"status": 400,
"detail": "Request validation failed",
"invalid-params": [
{
"name": "name",
"reason": "Name is required"
}
]
}
Modern PetstoreAPIは、すべてのエラー応答にRFC 9457形式を使用します。
401 Unauthorized
使用場面:認証情報がない、または無効。
GET /pets
401 Unauthorized
WWW-Authenticate: Bearer realm="PetstoreAPI"
{
"type": "https://petstoreapi.com/errors/authentication-required",
"title": "Authentication Required",
"status": 401,
"detail": "Valid authentication credentials required"
}
要点:
WWW-Authenticateヘッダーを含める- クライアントは資格情報またはリフレッシュトークンを要求すべき
- 403(認可)と混同しない
403 Forbidden
使用場面:認証されたユーザーに権限がない。
DELETE /pets/019b4132-70aa-764f-b315-e2803d882a24
403 Forbidden
{
"type": "https://petstoreapi.com/errors/insufficient-permissions",
"title": "Insufficient Permissions",
"status": 403,
"detail": "You don't have permission to delete this pet"
}
401との違い:
- 401:「あなたは誰ですか?」(認証)
- 403:「あなたが誰かは知っていますが、それはできません」(認可)
404 Not Found
使用場面:リソースが存在しない。
GET /pets/nonexistent-id
404 Not Found
{
"type": "https://petstoreapi.com/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "Pet not found"
}
使用しない場面:認可失敗(403を使用)、バリデーションエラー(400を使用)。
409 Conflict
使用場面:重複やバージョン不一致などのリソースの競合。
POST /pets
409 Conflict
{
"type": "https://petstoreapi.com/errors/duplicate-resource",
"title": "Duplicate Resource",
"status": 409,
"detail": "A pet with this microchip ID already exists"
}
422 Unprocessable Entity
使用場面:有効なリクエスト形式だがセマンティックエラー。
POST /pets
422 Unprocessable Entity
{
"type": "https://petstoreapi.com/errors/business-rule-violation",
"title": "Business Rule Violation",
"status": 422,
"detail": "Cannot adopt more than 5 pets per household"
}
400との違い:
- 400:不正な形式のリクエスト(無効なJSON、誤った型)
- 422:整形式のリクエストだがビジネスルールに違反
429 Too Many Requests
使用場面:レート制限超過。
GET /pets
429 Too Many Requests
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 1678886400
{
"type": "https://petstoreapi.com/errors/rate-limit-exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "Rate limit of 100 requests per hour exceeded"
}
Modern PetstoreAPIはIETFレート制限ヘッダーを使用しています。
サーバーエラーコード (5xx)
サーバーエラーコードはサーバーが失敗したことを示します。クライアントはこれらのリクエストを再試行できます。
500 Internal Server Error
使用場面:予期せぬサーバーエラー。
GET /pets
500 Internal Server Error
{
"type": "https://petstoreapi.com/errors/internal-error",
"title": "Internal Server Error",
"status": 500,
"detail": "An unexpected error occurred"
}
含めないこと:スタックトレース、内部詳細、本番環境でのデータベースエラー。
503 Service Unavailable
使用場面:一時的なサービス停止(メンテナンス、過負荷)。
GET /pets
503 Service Unavailable
Retry-After: 3600
{
"type": "https://petstoreapi.com/errors/service-unavailable",
"title": "Service Unavailable",
"status": 503,
"detail": "Service temporarily unavailable for maintenance"
}
クライアントに再試行のタイミングを伝えるためにRetry-Afterヘッダーを含めます。
Modern PetstoreAPIでのステータスコードの使用方法
Modern PetstoreAPIは、すべてのエンドポイントで適切なHTTPセマンティクスを実装しています。
例:ペット管理
// ペット一覧
GET /pets
200 OK
// ペット作成
POST /pets
201 Created
Location: https://petstoreapi.com/pets/{id}
// ペット取得
GET /pets/{id}
200 OK (見つかった場合) または 404 Not Found
// ペット更新
PUT /pets/{id}
200 OK (ボディ付き) または 204 No Content
// ペット削除
DELETE /pets/{id}
204 No Content (成功) または 404 Not Found
エラー応答
すべてのエラーはRFC 9457形式を使用します。
{
"type": "https://petstoreapi.com/errors/validation-error",
"title": "Validation Error",
"status": 400,
"detail": "Request validation failed",
"instance": "/pets",
"invalid-params": [
{
"name": "name",
"reason": "Name must be between 1 and 100 characters"
}
]
}
完全な例については、Modern PetstoreAPIのエラーハンドリングドキュメントを参照してください。
Apidogでステータスコードをテストする
Apidogは、すべてのシナリオでステータスコードの動作をテストするのに役立ちます。
期待されるステータスコードを定義する
paths:
/pets:
post:
responses:
'201':
description: Pet created
'400':
description: Validation error
'401':
description: Authentication required
'429':
description: Rate limit exceeded
すべてのシナリオをテストする
テストケースを作成する:
- 成功シナリオ(200, 201, 204)
- バリデーションエラー(400, 422)
- 認証/認可(401, 403)
- 見つからない(404)
- レート制限(429)
- サーバーエラー(500, 503)
自動テスト
// Apidogテストスクリプト
pm.test("成功した作成に対して201を返す", () => {
pm.response.to.have.status(201);
pm.response.to.have.header("Location");
});
pm.test("必須フィールドの欠落に対して400を返す", () => {
pm.response.to.have.status(400);
pm.expect(pm.response.json().type).to.include("validation-error");
});
避けるべき一般的な間違い
間違い1:POSTに200を使用する
// 間違い
POST /pets
200 OK
// 正しい
POST /pets
201 Created
Location: https://petstoreapi.com/pets/{id}
間違い2:DELETEに200を使用する
// 間違い
DELETE /pets/{id}
200 OK
{"message": "Deleted successfully"}
// 正しい
DELETE /pets/{id}
204 No Content
間違い3:401と403を混同する
// 間違い:ユーザーは認証されているが権限がない
401 Unauthorized
// 正しい
403 Forbidden
間違い4:クライアントエラーに500を使用する
// 間違い:バリデーションエラーが500を返す
POST /pets
500 Internal Server Error
// 正しい
POST /pets
400 Bad Request
まとめ
HTTPステータスコードはオプションではありません。それらはHTTP仕様の一部であり、適切なREST APIを構築するために不可欠です。
正しいステータスコードを使用する:
- 成功した読み取りには200
- 成功した作成には201
- 成功した削除には204
- クライアントエラーには400
- 認証には401
- 見つからない場合には404
- サーバーエラーには500
Modern PetstoreAPIは、すべてのエンドポイントで正しいステータスコードの使用法を示しています。適切な実装を確認するために、REST APIドキュメントを参照してください。
APIがHTTP標準に準拠していることを確認するために、Apidogでステータスコードをテストしてください。
よくある質問
成功したDELETEには200と204のどちらを使用すべきですか?
204 No Contentを使用してください。これはレスポンスボディなしでの成功を示し、帯域幅を節約します。削除されたリソースに関する情報を返す必要がある場合にのみ200を使用します。
400と422の違いは何ですか?
400はリクエストが不正な形式であること(無効なJSON、誤った型)を意味します。422はリクエストが整形式だがビジネスルールに違反していることを意味します。
401と403はいつ使い分けるべきですか?
401は「認証してください」(資格情報がない、または無効)を意味します。403は「認証されていますが、権限がありません」(権限不足)を意味します。
ユーザーがアクセスできないリソースに対しては404と403のどちらを返すべきですか?
リソースが存在するがユーザーに権限がない場合は403を返します。不正なユーザーからリソースの存在を隠したい場合は404を返します。
すべてのステータスコードシナリオをテストするにはどうすればよいですか?
Apidogを使用して、成功、バリデーションエラー、認証失敗、見つからない、サーバーエラーのテストケースを作成します。CI/CDで自動テストを実行します。
レート制限にはどのステータスコードを使用しますか?
RateLimit-*ヘッダーと共に429 Too Many Requestsを使用します。クライアントに再試行のタイミングを伝えるためにRetry-Afterを含めます。
すべてのサーバーエラーに500を使用すべきですか?
予期せぬエラーには500を使用します。アップストリームサービスの失敗には502、一時的なサービス停止には503、タイムアウトには504を使用します。
Modern PetstoreAPIはエラーをどのように処理しますか?
すべてのエラーは適切なステータスコードとともにRFC 9457形式を使用します。例についてはエラーハンドリングドキュメントを参照してください。
