ウェブベースのエディターを使って同僚と重要なドキュメントを共同で作業しているとします。二人とも同時に同じドキュメントを開きました。あなたは30分かけて慎重に導入部分を書き直し、その間、同僚は結論部分に取り組んでいました。あなたが最初に「保存」をクリックし、あなたの変更は受け入れられました。その後、同僚が「保存」をクリックすると、彼らのバージョンがあなたの素晴らしい新しい導入部分を何の警告もなく完全に上書きしてしまいました。あなたの作業は「失われた更新の問題 (lost update problem)」の犠牲になったのです。
この苛立たしいシナリオこそ、428 Precondition Required
HTTPステータスコードが防ぐために設計されたものです。これはHTTP仕様の中でも、より洗練された先見的なステータスコードの一つであり、複数のユーザーによって同時に変更される可能性のあるリソースの保護メカニズムとして機能します。
これはよく知られたステータスコードではありませんが、安全で信頼性の高い、同時実行可能なAPI通信において非常に重要な役割を果たします。
では、HTTP ステータスコード 428 Precondition Required は具体的に何を意味するのでしょうか?いつ発生し、どのように適切に処理すればよいのでしょうか?
これは、あなたがどの版を更新しているか確認するまで、本の貸し出しを許可しない慎重な図書館員のようなものだと考えてください。サーバーが「変更を加える前に、このリソースの最新バージョンで作業していることを証明してください」と言っているようなものです。
共同作業アプリケーション、同時更新を処理するAPI、またはデータの一貫性が不可欠なシステムを構築している場合、428
を理解することは不可欠です。
まさにそれが、この詳細な解説で掘り下げる内容です。これにより、428が何を意味するのかだけでなく、なぜ存在するのか、そしてどのようにAPIを改善できるのかを理解することができます。
428
応答を正しく処理できることを保証します。それでは、HTTP 428 Precondition Required がどのように競合する更新の問題を解決するのかを見ていきましょう。
問題:恐るべき「失われた更新」
428
が存在する理由を理解するためには、それが解決する問題を認識する必要があります。マルチユーザーシステムでは、2人以上のユーザーがほぼ同時に同じリソースを更新しようとすると、いくつかの問題が発生する可能性があります。
- 失われた更新 (Lost Updates): 2番目の書き込みが、最初の書き込みの変更を取り込むことなく上書きしてしまうという典型的な問題です。
- 競合する変更 (Conflicting Changes): 2人のユーザーが同じリソースの異なる部分に異なる変更を加えることです。
- 古いデータの更新 (Stale Data Updates): ユーザーが古い情報に基づいて変更を加えることです。
従来のアプローチでは、条件付きヘッダーを含めることでクライアントが「正しいことをする」ことに依存することがよくありました。しかし、クライアントがそれを忘れてしまったらどうなるでしょうか?428
コードは、サーバーが適切な振る舞いを強制することを可能にします。
HTTP 428 Precondition Required は実際に何を意味するのか?
428 Precondition Required
ステータスコードは、オリジンサーバーがリクエストに条件を付けることを要求していることを示します。これは、クライアントが最新のデータで作業していることを証明するために、条件付きヘッダー(If-Match
や If-Unmodified-Since
など)を含めることをサーバーが義務付けている方法です。
応答には、どのような前提条件が必要かについての役立つ説明を含めるべきです。典型的な 428
応答は次のようになります。
HTTP/1.1 428 Precondition RequiredContent-Type: application/problem+json{ "type": "<https://example.com/probs/conditional-required>", "title": "Precondition Required", "detail": "This resource requires conditional requests. Please include an If-Match or If-None-Match header.", "instance": "/articles/123"}
サーバーは本質的にこう言っているのです。「この特定のリソースについては、無条件の更新は受け付けません。どのバージョンを変更しようとしているのかを私に示してください。」
より簡単に言えば、サーバーはリクエストを処理する前に、クライアントが If-Match
や If-Unmodified-Since
といった前提条件ヘッダーを含めることを期待しています。
その前提条件が含まれていない場合、サーバーはリクエストを拒否し、428 Precondition Required エラーで応答します。
公式RFC定義
428ステータスコードは、ウェブ通信と信頼性を向上させるためにいくつかの追加HTTPステータスコードを導入したRFC 6585で定義されています。
その内容は次のとおりです。
「428 (Precondition Required) ステータスコードは、オリジンサーバーがリクエストに条件を付けることを要求していることを示します。その目的は、『失われた更新』の問題を防ぐことです。この問題は、クライアントがリソースの状態をGETし、それを変更してサーバーにPUTする間に、第三者がそのリソースを変更してしまった場合に発生します。」
これは多くの専門用語ですが、本質は単純です。複数のクライアントが同時に同じリソースを変更する際のデータの整合性と上書きの回避に関するものです。
平易な言葉で説明する
このシナリオを想像してみてください。
Googleドキュメントでチームメイトとドキュメントを編集しているとします。ドキュメントを開き、いくつかの編集を加えて保存をクリックしますが、その間にチームメイトも変更を加えて、あなたよりも先に自分のバージョンを保存してしまいました。
このとき、バージョン管理がなければ、あなたの変更が彼らの変更を上書きしてしまいます。これこそ、428 Precondition Required ステータスコードがAPIで防ぐのに役立つことです。
これはクライアントにこう伝えます。
「このリソースを変更する前に、あなたが最新バージョンで作業していることを私に証明してください。」
なぜ428が導入されたのか?
RESTful APIや一般的なHTTP操作において、クライアントはリソースを読み取り、ローカルでいくつかの変更を加え、その後更新リクエストを送信することがあります。しかし、その間にリソースが変更されていた場合、無条件に更新を適用すると、より新しい変更を上書きしてしまう危険性があります。
クライアントに前提条件の指定を要求することで、サーバーは以下を保証します。
- クライアントが最新バージョンで作業している場合にのみ更新を行う。
- 競合するリクエストが検出され、回避される。
- データの整合性が維持される。
これは、同時操作や複数のユーザーをサポートするAPIにとって極めて重要です。
仕組み:条件付きリクエストの流れ
共同編集シナリオで 428
が失われた更新を防ぐのにどのように役立つか、完全な例を見ていきましょう。
ステップ1:ユーザーAがリソースを取得する
ユーザーAは現在のドキュメントを取得します。
GET /documents/123 HTTP/1.1
サーバーはドキュメントで応答し、この特定のリソースバージョンのユニークな識別子であるETagヘッダーを含めます。
HTTP/1.1 200 OKContent-Type: application/jsonETag: "abc123"{ "id": 123, "title": "Project Proposal", "content": "Original content...", "version": "abc123"}
ステップ2:ユーザーBが同じリソースを取得する
ほぼ同じ頃、ユーザーBもドキュメントをリクエストし、同じETagを取得します。
ステップ3:ユーザーAが条件なしで更新を試みる
ユーザーAはドキュメントを更新しようとしますが、条件付きヘッダーを含めるのを忘れてしまいます。
PUT /documents/123 HTTP/1.1Content-Type: application/json{ "id": 123, "title": "Project Proposal", "content": "User A's updated content...", "version": "abc123"}
ステップ4:サーバーの428応答
このエンドポイントは前提条件を要求するように設定されているため、サーバーは次のように応答します。
HTTP/1.1 428 Precondition RequiredContent-Type: application/json{ "error": "precondition_required", "message": "This resource requires conditional updates. Please include an If-Match header with the current ETag."}
ステップ5:ユーザーAが正しいヘッダーで再試行する
ユーザーAのアプリケーションは 428
応答を受け取り、適切な条件付きヘッダーで自動的に再試行します。
PUT /documents/123 HTTP/1.1Content-Type: application/jsonIf-Match: "abc123"{ "id": 123, "title": "Project Proposal", "content": "User A's updated content...", "version": "abc123"}
サーバーはこの条件付きリクエストを正常に処理し、新しいETagとともに 200 OK
を返します。
ステップ6:ユーザーBが更新を試みる
ユーザーBが古いETagで更新しようとすると、サーバーは 412 Precondition Failed
でそれを拒否できるようになり、失われた更新を防ぎます。
428と412 Precondition Failed:違いを理解する
これは、条件付きリクエストの世界における重要な区別です。
428 Precondition Required
: 「このリクエストを行うには、条件付きヘッダーを含める必要があります。」サーバーはクライアントが条件付きリクエストを使用することを強制しています。これは、その慣行を要求することに関するものです。412 Precondition Failed
: 「条件付きヘッダーを含めましたが、条件が満たされませんでした。」クライアントは条件を含めることで正しいことをしましたが、その条件が偽と評価されました(例:ETagが一致しなかった)。これは、失敗した条件に関するものです。
例え:
428
: クラブの用心棒が「入るには身分証明書を見せなければなりません」と言うようなものです。(慣行の要求)412
: 用心棒が身分証明書を確認し、「この身分証明書は期限切れです、入れません」と言うようなものです。(特定のチェックが失敗した)
なぜ428 Precondition Requiredが存在するのか
一見すると、面倒に思えるかもしれません。なぜクライアントに自由に更新させないのでしょうか?
さて、428ステータスが存在するのには正当な理由があります。それは、分散システムにおけるデータ損失を防ぎ、一貫性を確保するためです。
その目的をさらに詳しく見ていきましょう。
1. 失われた更新の防止
「失われた更新」の問題は、複数のクライアントが同じリソースを取得し、それぞれ独立して更新する際に発生します。前提条件がなければ、あるクライアントの更新が、別のクライアントの更新を黙って上書きしてしまう可能性があります。
428は、すべての変更がリソースが取得されてから変更されたかどうかをチェックすることを保証し、静かなデータ損失を防ぎます。
2. データの整合性の確保
If-Match
のような前提条件を要求することで、サーバーは更新がリソースの正しいバージョンにのみ適用されることを保証します。これは、データに安全ロックをかけるようなものです。
3. 安全な同時実行性の促進
共同編集、API統合、RESTfulサービスなど、多くのユーザーが共有リソースと対話するシステムにおいて、428は同時実行性管理をより予測可能で安全なものにします。
4. ベストプラクティスの奨励
条件付きリクエストを強制することで、サーバーは開発者に対し、ETag、条件付きGET、バージョンチェックなどのRESTful設計のベストプラクティスに従うよう促します。
428 Precondition Required をいつ使用するか
以下のシナリオで 428
の使用を検討すべきです。
1. 共同編集アプリケーション
複数のユーザーが同時に同じドキュメントを編集する可能性のあるGoogleドキュメントのようなアプリケーション。
2. 競合頻度の高いリソース
複数のソースから頻繁に更新されるあらゆるリソース。例えば:
- 製品の在庫数
- チケット予約システム
- 投票または評価システム
- 設定情報
3. 機密データの更新
誤って上書きされると、財務記録や医療データのように深刻な結果を招く可能性のあるリソース。
4. 安全のためのAPI設計
良好なクライアントの振る舞いを強制し、一般的な同時実行性の問題を防止したい場合。
428 Precondition Required の実世界シナリオ
1. 同時API編集
複数のクライアントが同時に同じレコードを変更する際、428は更新が互いに上書きされないようにします。
2. バージョン管理されたAPI
時間の経過とともに進化するAPIは、クライアントが互換性のあるバージョンを使用していることを保証するために前提条件を強制できます。
3. 楽観的ロックシステム
楽観的同時実行制御のためにETagを使用するデータベースやREST APIは、競合を検出するために前提条件に依存しています。
4. ファイルまたはオブジェクトストレージAPI
S3のようなクラウドストレージシステムは条件付きリクエストを多用しており、428はそのようなルールを強制するのに自然に適合します。
Apidogを使ったAPIテスト

同時実行制御を扱う際、Apidogはあなたの秘密兵器となります。条件付きリクエストフローのテストには、慎重な設定と複数のステップが必要です。Apidogはこのような種類のテストに完全に適しています。
Apidogを使えば、以下のことができます。
- 1. テストシナリオの作成: 完全なテストフローを構築します。
- まず、リソースを取得するために
GET
リクエストを送信し、そのETagヘッダーをキャプチャします。 - 次に、サーバーが
428
を返すことを確認するために、条件付きヘッダーなしでPUT
リクエストを送信します。 - 最後に、成功した更新を確認するために、キャプチャしたETagとともに
PUT
リクエストを送信します。 - 2. ヘッダー管理の自動化: Apidogの環境変数を使用して、リクエスト間でETag値を自動的に保存および再利用します。
- 3. 競合状態のシミュレーション: 異なるETagを持つ並列リクエストを送信することで、複数のユーザーが同じリソースを更新する状況をシミュレートするテストスイートを作成します。
- 4. エラー応答の検証:
428
応答に、クライアントがどのように異なる対応をする必要があるかをガイドする役立つエラーメッセージが含まれていることを確認します。 - 5. クライアントの回復力のテスト: クライアントアプリケーションが適切な条件付きヘッダーで再試行することで、
428
応答を正しく処理することを確認します。
実装のベストプラクティス
サーバー開発者向け:
- 一貫性を保つ: あるメソッド(
PUT
など)に前提条件を要求する場合、そのリソース上のすべての状態変更メソッドにも要求します。 - 明確なエラーメッセージを提供する:
428
応答には、どのヘッダーが必要か、現在のリソース状態をどのように取得するかを明確に説明する必要があります。 - 標準ヘッダーを使用する:
If-Match
、If-None-Match
、If-Modified-Since
、If-Unmodified-Since
などの標準的な条件付きヘッダーに固執します。 - グレースフルデグラデーションを検討する: 重要度の低いリソースの場合、前提条件の欠落をログに記録しつつも、リクエストを処理する場合があります。
クライアント開発者向け:
- 常に428を適切に処理する:
428
を受け取った場合、致命的なエラーとして扱わないでください。代わりに、現在のリソース状態を取得し、適切な条件付きヘッダーで再試行します。 - ETagをキャッシュする: 後続の更新に備えて、ローカルのリソースコピーとともにETagを保存します。
- 自動再試行ロジックを実装する:
428
応答を自動的に処理するために、再フェッチと再試行を行うロジックを構築します。
より大きな視点:堅牢なAPIの構築
428 Precondition Required
ステータスコードは、より堅牢で自己文書化されたAPIへの移行を表しています。クライアントに条件付きリクエストの使用を要求することで、あなたは次のことを行っています。
- データ損失の防止: 同時実行性のバグの全カテゴリーを排除する
- APIの安全性の向上: クライアントが誤ってデータを破損させるのをより困難にする
- ベストプラクティスの強制: クライアントを適切な使用パターンに導く
- より良い診断の提供: クライアントが間違いを犯したときに明確なフィードバックを与える
結論:リアクティブからプロアクティブなエラー処理へ
HTTP 428 Precondition Required
ステータスコードは、同時実行制御をオプションのベストプラクティスから強制可能な要件へと変革します。これにより、エラー処理がリアクティブ(「あなたの更新は他の誰かのものと競合しました」)からプロアクティブ(「あなたの更新を検討する前に、あなたが現在のデータで作業していることを証明する必要があります」)へと移行します。
これは追加のステップのように思えるかもしれませんが、このアプローチは最終的に、より信頼性の高いアプリケーションと、静かなデータ破損によって作業が失われることのない、より満足度の高いユーザーにつながります。
現代のウェブアプリケーションを構築する開発者にとって、428
を理解し実装することは、API設計における洗練の証です。これは、APIが何をするかだけでなく、複数のユーザーがいる実世界の条件下でどのように動作するかを考えていることを示します。
そして、これらの洗練された同時実行制御を実装およびテストする準備ができたら、Apidogのような強力なツールが、条件付きリクエストロジックが完璧に機能し、ユーザーのデータと精神的な安定を保護することを保証するために必要なテスト環境を提供します。