1. はじめに
Webアプリケーションの設計やRESTful APIの構築において、私たちは日常的にHTTPメソッドを使い分けています。「データを取得するからGET」「登録するからPOST」といった基本は、この業界にいるとほとんどの人が知っている知識です。
しかし、一歩進んだシステム設計を任されるようになると、以下のような設計の迷いに直面します。
- 「リソースの更新はPUTとPATCHのどちらを選ぶべきか」
- 「複雑な検索条件を投げたいが、URLの長さ制限を避けるためにPOSTで検索APIを作っても良いのか」
なんとなくの雰囲気でメソッドを選んでいると、キャッシュ戦略の破綻や、リトライ処理によるデータ不整合(二重課金や重複登録など)といった深刻なバグを引き起こします。
本記事では、改めて一から堅牢なシステムを設計・実装するエンジニアに向けて、HTTPメソッドの本質である「安全性」と「べき等性」を言語化します。さらに、各主要メソッドの深掘りと、2026年6月に登場した待望の最新仕様「QUERY」メソッドまでを徹底的に解説します。
2. HTTPメソッドの「安全性」と「べき等性」を正しく言語化する
APIの挙動を正しくコントロールするための最重要概念が、安全性(Safe)とべき等性(Idempotent)です。まずはこの2つの定義を明確にします。
安全性(Safe)とは
リクエストを送信しても「サーバー上のリソースの状態を変更しない(読み取り専用)」という性質です。
- 身近な例え: 「本棚から本を取り出して読むだけ」の状態です。本の内容も本棚の並びも変わりません。
べき等性(Idempotent)とは
「ある操作を1回行っても、複数回行っても、サーバーの最終的な状態がすべて同じになる」という性質です。
- 身近な例え: エレベーターの「閉」ボタンです。1回押しても、イライラして10回連打しても、「ドアが閉まる」という最終的な結果は変わりません。
【早見表】主要HTTPメソッドの特徴一覧
| メソッド | 安全性 | べき等性 | 主な用途 | リクエストボディ |
|---|---|---|---|---|
| GET | ◯ | ◯ | リソースの取得 | 原則なし |
| POST | × | × | 新規リソースの作成・その他 | あり |
| PUT | × | ◯ | リソースの完全置換(または作成) | あり |
| PATCH | × | × | リソースの部分更新 | あり |
| DELETE | × | ◯ | リソースの削除 | なし(例外あり) |
| HEAD | ◯ | ◯ | ヘッダー情報のみの取得 | なし |
| OPTIONS | ◯ | ◯ | 通信オプションの調査(CORS等) | なし |
| QUERY(最新) | ◯ | ◯ | 複雑な条件によるリソース検索 | あり |
この「安全性」と「べき等性」が保証されているからこそ、ブラウザやCDNは安心してデータをキャッシュでき、ネットワークエラー発生時にクライアントが自動でリトライを試みることができます。
3. 主要HTTPメソッドの徹底深掘りと実務での罠
主要なメソッドについて、具体的な使用例と、実務で設計を誤ると発生するバグや罠を深掘りします。
① GET (リソースの取得)
- 本質: サーバーから特定の情報を取得します。安全かつべき等です。
-
正しい使用例:
GET /users/123(ユーザーID 123の情報を取得) -
実務での罠(アンチパターン): 「ページが表示された回数をカウントしたいから」という理由で、
GET /articles/456/increment-viewのように、GETリクエストの内部処理でDBのカウントをインクリメントする設計。
GETは「安全」であると見なされるため、検索エンジンのクローラーがURLを巡回しただけで、意図せずカウントが爆増します。状態の変更を伴う処理にGETを使ってはいけません。
② POST (新規リソースの作成・その他)
- 本質: サーバーに新しい子リソースを作成するか、他のメソッドに当てはまらない汎用的な処理(コントローラー処理)を実行します。安全でもべき等でもありません。
-
正しい使用例:
POST /orders(新しい注文を確定する) -
実務での罠(アンチパターン):
決済処理を行うAPIで、ネットワークの瞬断によりクライアントが同じPOSTリクエストを再送したケース。POSTはべき等ではないため、サーバー側で重複排除(冪等キーの導入など)を行わないと、2回分の課金が発生する「二重決済バグ」の原因になります。
③ PUT (リソースの完全置換)
- 本質: 指定したURLのリソースを、リクエストボディの内容で「完全に置き換え」ます。存在しない場合は新規作成します。べき等です。
-
正しい使用例:
PUT /users/123/profile(プロフィール情報を丸ごと最新状態に上書きする) -
実務での罠(アンチパターン):
後述する「PATCH」との混同です。リクエストボディに含まれていない項目を「変更なし」とみなしてスルーする実装をPUTで行うのは間違いです。仕様上、送信されなかった項目は「削除(またはデフォルト値にリセット)」として処理しなければなりません。
④ PATCH (リソースの部分更新)
- 本質: 既存のリソースの一部を「修正(パッチ)」します。原則としてべき等ではありません(実装によってべき等にすることは可能ですが、仕様上は保証されません)。
-
正しい使用例:
PATCH /users/123(リクエストボディ:{"email": "new@example.com"}でメールアドレスだけを書き換える) -
実務での罠(アンチパターン):
「相対的な更新」を行う場合です。例えば、PATCH /products/789に対して{"stock_increment": 5}(在庫を5増やす)というパッチを当てた場合、リクエストを3回送ると在庫が15増えてしまいます。これが、PATCHが「べき等ではない」とされる理由です。
⑤ DELETE (リソースの削除)
- 本質: 指定したURLのリソースを削除します。べき等です。
-
正しい使用例:
DELETE /posts/999(記事ID 999の削除) -
解説:
1回目のDELETEでリソースは削除され、ステータスコード200 OKまたは204 No Contentが返ります。2回目に同じURLにDELETEを送ると、すでにリソースがないため404 Not Foundが返るのが一般的です。
「返ってくるステータスコードが変わるのにべき等なのか?」と疑問に思うかもしれませんが、重要なのは「サーバー上のリソースの状態(=すでに消えている)」が2回目以降も変わらない点です。したがって、DELETEはべき等です。
4. 実務で100回は迷う「PUT」と「PATCH」の決定的な違い
API設計において、もっとも議論になりやすいのが「更新APIにPUTとPATCHのどちらを使うべきか」です。この2つの本質的な違いは、データの「完全置換」か「部分更新」かです。
実務でよく発生する「null上書き問題」を例に挙げます。
ユーザー情報のスキーマが { "id": 1, "name": "Tanaka", "age": 30 } だとします。
ここで、年齢(age)だけを31歳に更新したい場合を考えます。
PUTを選択した場合
PUTは「完全置換」です。クライアントは、変更のない name も含めたすべてのデータを送信する必要があります。
PUT /users/1
Content-Type: application/json
{
"name": "Tanaka",
"age": 31
}
もし、ジュニアエンジニアが以下のようなリクエストを送信してしまったらどうなるでしょうか。
PUT /users/1
Content-Type: application/json
{
"age": 31
}
正しいPUTの実装であれば、送信されなかった name は null に上書きされるか、スキーマ違反でエラーになります。もし、サーバー側で「送られてこなかった name は既存のデータ(Tanaka)を維持しよう」と温情な処理をしてしまうと、それはPUTではなくPATCHの挙動になってしまい、APIのセマンティクスが崩壊します。
PATCHを選択した場合
PATCHは「部分更新」です。変更したい差分(デルタ)だけを送信します。
PATCH /users/1
Content-Type: application/json
{
"age": 31
}
この場合、サーバーは name には手を付けず、age だけを安全に更新します。
設計の指針
- クライアントがリソースの「現在の全状態」を把握して管理している場合は PUT。
- 画面の一部分(例:設定トグルスイッチ、ステータス変更のみ)からピンポイントで更新したい場合は PATCH。
実務のWebアプリケーションでは、画面の一部だけを書き換えるユースケースが大半を占めるため、PATCHを選択する方が自然で頑健な設計になることが多いです。
5. 「GET vs POST」の限界と、検索APIのジレンマ
私たちは長年、リソースの検索(Read操作)において不健全な妥協を強いられてきました。
本来、情報の検索は「安全」かつ「べき等」であるため、GETメソッドを使うべきです。しかし、実務のシステム(特に業務システムや複雑なECサイトの検索)では、以下のような過酷な要件が発生します。
- 検索条件の項目が50個以上ある。
- ネストされた複雑なJSON構造で検索条件を指定したい。
- ユーザーが入力した長大なフリーワードや、IDの配列(1000個のIDなど)を条件に含めたい。
GETリクエストは、条件をURLのクエリパラメータ(?status=active&type=premium...)に載せる必要があります。しかし、ブラウザやWebサーバー、CDNには「URLの長さ制限(例:IEの名残りである2,048バイトや、モダンな環境でも約8KB〜16KB)」が存在します。これを超えると、414 URI Too Long エラーで通信が落ちます。
また、GETでリクエストボディ(Payload)を送ることは、HTTP/1.1やHTTP/2の仕様上「禁止はされていないが、セマンティクス(意味論)が定義されていない」状態です。そのため、多くのWebサーバーやプロキシ(nginxや各種ロードバランサー)でGETのリクエストボディは無視されるか、エラーではじかれます。
結果として、多くのエンジニアは涙をのんで以下の設計を選択してきました。
POST /users/search
Content-Type: application/json
{
"status": "active",
"tags": ["premium", "verified"],
"registered_after": "2026-01-01",
"excluded_ids": [102, 105, 309, ...(大量のID)]
}
「リソースを新規作成するわけではない(安全・べき等な読込である)」にもかかわらず、URL長制限を回避するためだけにPOSTを使っているのです。
これにより、以下のような弊害が発生します。
- 読み取り専用のAPIなのに、WebサーバーやCDNによる自動的なキャッシュが効かない。
- ブラウザの「戻る」ボタンを押した際、「フォーム再送信の確認」という不快なダイアログがユーザーに表示される。
6. 【最新技術動向】ついに標準化!第三の選択肢「QUERY」メソッド(RFC 10008)
この「GET vs POST」の不毛なジレンマに、ついに終止符が打たれました。
IETF(Internet Engineering Task Force)は、2026年6月、新しいHTTPメソッドである「QUERY」を RFC 10008 として正式に発行(Proposed Standard)しました。
QUERYメソッドとは何か?
一言で言えば、「安全かつべき等(GETの性質)でありながら、リクエストボディを持てる(POSTの性質)メソッド」です。
QUERY /users
Content-Type: application/json
{
"filters": {
"status": "active",
"age_range": [20, 35]
},
"sort": "registered_at_desc"
}
QUERYメソッドがもたらす破壊的なメリット
- URL長制限からの解放: どれほど複雑で長大な検索条件であっても、リクエストボディにJSONやGraphQL、あるいはSQLライクな構造を安全に格納できます。
- 安全・べき等性の担保: メソッド自体が「安全(Safe)」と定義されているため、Webサーバーや中継するCDNは、リクエストボディの内容をハッシュ値などのキーにして、検索結果を安全にキャッシュ(Cache)可能になります。
- ブラウザフレンドリー: 検索結果の画面でブラウザの「戻る」を押しても、POSTのような警告画面は出ません。
2026年現在の導入ロードマップ
RFC 10008として正式に標準化されたため、モダンなWebフレームワーク(Node.js環境のHono、Python、Goのフレームワークなど)や、主要なリバースプロキシでのネイティブサポートが急速に進んでいます。
新規のプロダクト開発や、社内マイクロサービス間の通信において、複雑な検索クエリを投げるAPIを設計する際は、従来の「妥協のPOST」ではなく、この「QUERYメソッド」の採用を第一候補として検討する時代が到来しています。
7. まとめ:明日から使えるAPI設計チェックリスト
適切なHTTPメソッドの選択は、システムのパフォーマンス、セキュリティ、そして堅牢性に直結します。設計フェーズで迷ったら、以下のチェックリストを上から順に確認してください。
-
その操作はサーバーの状態を変えない(読み取り専用)か?
-
YES → 基本は
GET。 -
条件が多すぎてURLに収まらない、または構造化データを送りたい場合は最新の
QUERYを検討。 -
その操作はリソースの「新規作成」か?
-
YES →
POST。 -
その操作は既存データの「更新」か?
-
クライアントがデータの全貌を持っており、丸ごと差し替える(完全置換) →
PUT。 -
特定の項目だけをピンポイントで書き換える(部分更新) →
PATCH。 -
その操作はリソースの「削除」か?
-
YES →
DELETE。 -
通信エラー時の自動リトライを安全に行いたいか?
-
べき等である必要あり。
GET/QUERY/PUT/DELETEを選択。POSTやPATCHを使う場合は、アプリケーション層での重複排除(冪等キー)を実装する。
正しい言語化とセマンティクスの理解をもって、美しいAPIを設計していきましょう。
8. 参考リンク集
さらに仕様の深い背景を学びたい方は、以下の公式ドキュメントを参照してください。