【実務・中級編】HTTP/1.1におけるPUTメソッドの冪等性とリソース置換 – HTTPプロトコル・通信規格実践ガイド

HTTP/1.1の「PUT」を正しく使いこなす:冪等性とリソース置換の深い話

Web APIを設計する際、`GET`で取得し、`POST`で作成し、`DELETE`で消す。ここまでは誰でも通る道だ。しかし、実務の現場で「リソースの更新」を設計する段になると、`PUT`と`PATCH`、あるいは`POST`の使い分けで手が止まるエンジニアが多い。

今日は、HTTP/1.1の仕様において最も誤解されやすく、かつ強力なメソッドである`PUT`の本質について、現場のインフラ視点から深掘りしていこう。なぜ`PUT`は「冪等(べきとう)」でなければならないのか。そして、なぜそれが「完全置換」なのか。その意味を理解すれば、APIの堅牢性は一段階引き上がる。

—

1. PUTの定義:それは「上書き」ではなく「置換」だ

RFC 9110(旧RFC 7231)において、`PUT`メソッドは「ターゲットリソースの現在の状態を、リクエストのペイロードで提供された状態に置換する」と定義されている。

ここで重要なのは、「リソースそのものを差し替える」という概念だ。`PATCH`のように一部のフィールドだけを更新する差分更新ではない。`PUT`は、指定したURIに送られてきたデータが「そのリソースの全て」であると見なす。

なぜ「冪等(Idempotency)」が重要なのか

冪等とは、「同じ操作を何回繰り返しても、システムの状態が変わらない」性質を指す。
例えば、ネットワーク障害でパケットがロスし、クライアントが再送を試みる場面を想像してほしい。

  • POSTの場合: 2回送ると、2回分リソースが作成される可能性がある(非冪等)。
  • PUTの場合: 1回目も2回目も「URIの結果がこのデータであること」を保証するため、何回実行しても最終的なリソースの状態は同じになる(冪等)。

この「何度叩いても安全」という性質こそが、信頼性の高い分散システムを構築する際の生命線となる。

—

2. 通信フローから見るPUTの挙動

`PUT`リクエストのシーケンスは非常にシンプルだ。しかし、インフラエンジニアとしては「中身」に注目する必要がある。

[Client] [Server]
| |
|– PUT /users/123 —->| <- URIで対象リソースを特定 | { "name": "Alice" } | <- ボディでリソースを完全定義 | | |<-- 200 OK / 204 No C--| <- 成功なら状態を報告 | | もし、サーバー側が指定されたURIにリソースを持っていない場合、`PUT`は新規作成(Create)として振る舞うことも仕様上許容されている。しかし、その場合でも「URIはクライアントが決定する」という点が`POST`との決定的な違いだ。 ---

3. 実践:PUTを叩くためのコード実装

理論だけでは現場は回らない。実際に`curl`や`Python`を用いて、この挙動を検証してみよう。

curl での検証

既存のリソースを完全に置き換える
curl -X PUT https://api.example.com/items/5 \
-H “Content-Type: application/json” \
-d ‘{“name”: “Updated Item”, “price”: 1500}’ # このデータが全てとなる

Python (requests) での検証

import requests

url = “https://api.example.com/items/5”
payload = {“name”: “Updated Item”, “price”: 1500}

冪等性を意識したPUTリクエスト
ネットワークエラーが発生しても、再送すれば結果は同じになる
response = requests.put(url, json=payload)

if response.status_code in [200, 204]:
print(“リソースの置換に成功しました”)
else:
print(f”エラー発生: {response.status_code}”)

—

4. 現場でハマる「落とし穴」とデバッグの極意

私がこれまで見てきた障害の中で、`PUT`にまつわるトラブルは以下の2点に集約されることが多い。

① 「部分更新」をPUTで行ってしまう設計ミス

「名前だけ変えたいのに、`PUT`を送ったら他のフィールドが消えた」という問い合わせは後を絶たない。これは`PUT`が完全置換であることを忘れた設計によるものだ。部分更新が必要なら、素直に`PATCH`を使うか、API側でリソースのバリデーションを厳格に行う必要がある。

② 冪等性が崩れる実装(サーバー側の副作用)

サーバー側で`PUT`の処理内に「カウンターをインクリメントする」といった副作用を仕込むと、冪等性は即座に破綻する。
「PUTのハンドラーにはカウンターもログの重複記録も入れない」。これが鉄則だ。

トラブルシューティングTips

もし、`PUT`を叩いたはずなのに予期せぬ挙動をする場合は、まず以下を確認せよ。

1. HTTPステータスコード: `200 OK` なのか `201 Created` なのか。`201`が返っているなら、クライアントは「新規作成」を意図していないのにサーバーがそう解釈している可能性がある。
2. キャッシュ: `PUT`に対するキャッシュが中間プロキシ(CDN等)で効いていないか確認せよ。通常`PUT`はキャッシュされないが、不適切な設定は時に悪さをする。
3. リクエストボディの妥当性: サーバー側で「足りないフィールド」をどう扱っているか(NULLで埋めるのか、デフォルト値を入れるのか)。ここが不明確だと、クライアント側でリソースを破壊する原因になる。

—

最後に:プロトコルを信じるということ

`PUT`を正しく使うということは、ネットワークの不安定さとどう向き合うかを定義することに他ならない。冪等性を理解し、リソースのライフサイクルを制御できるようになれば、あなたのAPIはネットワークの揺らぎに対しても強靭なものになるはずだ。

次は、`PATCH`メソッドを使った差分更新の安全な実装について議論しよう。あれはあれで、また面白い沼が待っている。

現場からは以上だ。何かあればまたいつでも聞いてくれ。

コメント

タイトルとURLをコピーしました