3秒でわかる
リクエストで何をしたいかを示す動詞。GET で取得、POST で作成、PUT で更新、DELETE で削除と、同じ URL でも操作を区別できます。
もう少し詳しく
どういうものか
HTTP メソッドは、リクエストの 1 行目に置かれる動詞で、対象のリソースに対して何をしたいかを表す。GET /api/users/42 なら「42 番の利用者を取得する」という意味になる。
Web API の設計では、URL がリソース (名詞) を表し、メソッドが操作 (動詞) を表す。だから /api/getUser のように URL 側へ動詞を入れる必要が無く、/api/users/42 の 1 本で取得も更新も削除も表せる。
なぜ必要か
メソッドが分かれていることで、途中の経路が中身を読まずに扱いを判断できる。GET は何も変えない読み取りなので、プロキシや CDN がキャッシュしてよい。POST は状態を変えるのでキャッシュしない。ブラウザが POST した画面の再読み込みで再送の確認を出すのも、この区別に基づく。
もう 1 つ、冪等性 (何度実行しても結果が変わらない性質) の扱いに直結する。通信が途中で切れて成否が分からないとき、GET PUT DELETE はそのまま再送してよいが、POST の再送は二重登録になる。
具体例
// 取得 ── ボディを持たない
await fetch("/api/users/42");
// 作成 ── サーバーが id を採番する。成功は 201 を返す
await fetch("/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "佐藤", email: "sato@example.com" }),
});
// 全体更新 ── 送らなかった項目は消える扱いになる
await fetch("/api/users/42", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "佐藤", email: "sato.new@example.com" }),
});
// 部分更新 ── 送った項目だけ変える
await fetch("/api/users/42", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "sato.new@example.com" }),
});
// 削除
await fetch("/api/users/42", { method: "DELETE" });つまずきやすいところ
GET でデータを変える実装が最も危うい。/api/posts/12/delete を GET で受けると、クローラや先読みが踏んだだけで消える。状態を変える操作は GET に置かない。
PUT と PATCH の取り違えも起きる。PUT は本来そのリソース全体の置き換えなので、一部の項目だけを送ると残りが空になる実装がある。部分更新は PATCH を使う。
HTML のフォームは GET と POST しか出せない。PUT と DELETE を使う API はブラウザの fetch から呼ぶか、_method のような隠し項目でサーバー側に読み替えさせる。
似た用語との違い
| メソッド | 安全 (状態を変えない) | 冪等 | 主な成功時のコード |
|---|---|---|---|
| GET | はい | はい | 200 |
| POST | いいえ | いいえ | 201 |
| PUT | いいえ | はい | 200 / 204 |
| PATCH | いいえ | 保証されない | 200 |
| DELETE | いいえ | はい | 204 |
DELETE を 2 回投げると 2 回目は対象が無いが、「その id が存在しない」という結果は同じなので冪等として扱う。