フロントエンドエンジニアとして数年やってきて「HTTPはわかっている」と思っていた。fetch でAPIを叩けるし、GET と POST の違いも説明できる。だが「Webを支える技術」を読んで、自分が「使えている」と「理解している」の間には大きな溝があることを認識した。
HTTPは仕様として定義されたプロトコルであり、各メソッドやステータスコードには明確な意味と制約がある。「なんとなくPOSTでデータを送っている」ではなく、RFCの意図を理解して設計するのがエンジニアとしての本来の姿勢だ。
HTTPメソッドを正確に使い分ける
よく使う5つのメソッドの定義を整理する。
| メソッド | 意味 | 冪等性 | 安全性 |
|---|---|---|---|
| GET | リソースの取得 | あり | あり |
| POST | リソースの作成 | なし | なし |
| PUT | リソースの完全置換 | あり | なし |
| PATCH | リソースの部分更新 | なし(実装依存) | なし |
| DELETE | リソースの削除 | あり | なし |
「冪等性」と「安全性」はHTTPの仕様で定義されている重要な概念だ。
安全性(Safe) とは、リクエストを送ってもサーバ側の状態を変更しないことを意味する。GETとHEADが該当する。ブラウザが勝手にリンクを先読みしたり、検索クローラーがリンクを踏んだりしても安全なのは、GETが副作用を持たないという前提があるからだ。
冪等性(Idempotent) とは、同じリクエストを何度送っても結果が変わらないことを意味する。GET・PUT・DELETEが該当する。ネットワーク障害でリトライが発生しても安全に再送できる。
この理解があると「なぜ削除APIをPOSTで実装するのが問題か」が説明できる。DELETEは冪等なので何度叩いても同じ結果(最終的にリソースが存在しない状態)になるはずだが、POSTでAPIを設計するとその保証が失われる。
POSTとPUTとPATCHの実務的な使い分け
ここが一番迷いやすいポイントだ。
POST は「サーバがURLを決めるリソースの作成」に使う。
POST /articles
→ サーバが /articles/123 を発行して返す
PUT は「クライアントがURLを指定したリソースの完全置換」に使う。存在しなければ作成、存在すれば全フィールドを上書きする。
PUT /articles/123
→ /articles/123 のリソース全体を送信データで置き換える
PATCH は「リソースの一部だけを更新する」。PUTと違い、送らなかったフィールドはそのまま保持される。
PATCH /articles/123
{ "title": "新しいタイトル" }
→ title だけ更新、他のフィールドは変わらない
フロントエンドからAPIを設計するとき、更新APIを雑に POST /updateArticle とするのではなく PATCH /articles/:id とすることで、HTTPの仕様に沿った意図の明確なAPIになる。
ステータスコードを正確に使う
「200 OK」「404 Not Found」は誰でも知っているが、実務でよく迷うコードを整理する。
200番台(成功)
| コード | 意味 | 使いどころ |
|---|---|---|
| 200 OK | 成功 | GET・PUT・PATCHの成功 |
| 201 Created | リソース作成成功 | POSTの成功、Locationヘッダーで作成先URLを返す |
| 204 No Content | 成功だがレスポンスボディなし | DELETEの成功 |
DELETEが成功したとき 200 を返してボディに {"success": true} を返すAPIをよく見るが、204 No Content の方がHTTPの意味論に沿っている。ボディがないことで「削除したからもうリソースはない」という意味が明確になる。
400番台(クライアントエラー)
| コード | 意味 | 使いどころ |
|---|---|---|
| 400 Bad Request | リクエスト不正 | バリデーションエラー |
| 401 Unauthorized | 認証が必要 | 未ログイン状態 |
| 403 Forbidden | アクセス禁止 | 権限不足 |
| 404 Not Found | リソースが存在しない | URLが見つからない |
| 409 Conflict | 状態の競合 | 重複登録の防止 |
| 422 Unprocessable Entity | 処理できないエンティティ | セマンティックエラー |
401 と 403 の違いは重要だ。401 は「誰かわからない(認証が必要)」、403 は「誰かはわかったが許可していない(認可の失敗)」だ。未ログインユーザーが保護されたAPIにアクセスした場合は 401、ログイン済みだが管理者専用リソースにアクセスした場合は 403 が正しい。
キャッシュ制御ヘッダー
HTTPヘッダーの中でも特にキャッシュ関連は誤解が多い。
Cache-Control: max-age=3600, public
Cache-Control: no-store
Cache-Control: no-cache
ETag: "abc123"
Last-Modified: Mon, 18 May 2026 10:00:00 GMT
no-cache は「キャッシュしない」ではなく「毎回サーバに再検証してから使う」という意味だ。no-store が「キャッシュを一切保存しない」に該当する。この違いを間違えると、意図したキャッシュ動作にならない。
ETag と Last-Modified は条件付きリクエストに使われる。ブラウザが If-None-Match: "abc123" をリクエストに含めて送ると、サーバはリソースが変わっていなければ 304 Not Modified を返す。これによってボディの転送を省略できる。CDNのキャッシュ設計を理解するには、このヘッダーの仕組みが欠かせない。
Content-Typeとメディアタイプ
Content-Type の指定は正確に行う必要がある。
Content-Type: application/json; charset=utf-8
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
Content-Type: application/x-www-form-urlencoded
JSON APIでは application/json を明示する。text/plain でJSONを返しているAPIを見かけることがあるが、クライアントが自動パースできなくなるリスクがある。ファイルアップロードは multipart/form-data が正しく、HTMLフォームのデフォルトは application/x-www-form-urlencoded だ。
治験EDCシステムのAPI設計でHTTP仕様が問われた話
医療系スタートアップで治験データ収集システム(EDC)のAPIを設計したとき、HTTP仕様への理解が実際の設計品質に差を生んだ体験がある。
EDCシステムでは「被験者の同意取得記録」や「有害事象の報告」など、更新してはいけないデータと上書きできるデータが混在する。最初は雑に全部 POST /update-xxx で設計していたが、製薬会社側のシステムとのAPI連携仕様書を作成する際、「これは冪等性がありますか?」と問われて答えられなかった。
それを機にHTTPメソッドの意味を正確に理解し直した。
同意記録は一度作成したら変更できない(POST /consents のみ)。有害事象の重篤度評価は上書き可能だが全フィールド置換(PUT /adverse-events/:id)。コメントなど一部フィールドのみの更新は PATCH。このように設計を整理したことで、「どのAPIは安全にリトライできるか」「どのAPIは一度しか呼んではいけないか」がメソッドを見るだけで判断できるようになった。
ステータスコードの話も実感した。401 と 403 の違いが曖昧なままだと、モニタリング担当者(CRA)が権限外のデータにアクセスしようとしたときに「ログインしていない」と誤解させるUIになってしまう。403 Forbidden を正確に返すことで、フロントエンドが「権限がないため表示できません」と正しいメッセージを出せた。
「なんとなく動く」APIから「意図が明確な」APIへの変化は、連携先との仕様合意がしやすくなるという副次効果も大きかった。
まとめ
HTTPを「使えている」と「理解している」の差は、設計の質に直結する。
メソッドの冪等性・安全性を理解してAPIを設計すると、リトライの安全性が上がり、クライアントの実装がシンプルになる。ステータスコードを正確に返すと、エラーの種類をコード側で判断しやすくなる。ヘッダーを正しく設定すると、キャッシュ効率が上がりパフォーマンスが改善する。
フロントエンドエンジニアがバックエンドやAPI設計に関わる機会が増えた現代では、HTTPの仕様を正確に理解しておくことは基礎教養のひとつだと思っている。