メインコンテンツにスキップ

📬 HTTPメソッド

📖 定義

HTTPメソッドは、クライアントがサーバーに実行してほしい動作を示します。各メソッドは特定の意味と用途を持ち、RESTful API設計の核心です。

🎯 比喩で理解する

図書館システム

GET    = 本を探す (取得)
├─ 司書に「この本はありますか?」と尋ねる
├─ データを取得するだけ
└─ 図書館の状態に変化なし

POST = 新刊を登録する (作成)
├─ 新しい本を図書館に追加
├─ 図書館の状態に変化
└─ 新しいリソースを作成

PUT = 本の情報を全体的に修正 (全体更新)
├─ 本のすべての情報を新しく書き直す
└─ 全体を置き換える

PATCH = 本の情報を部分的に修正 (部分更新)
├─ 本の一部の情報のみ修正 (例: 貸出可否)
└─ 一部のみ変更

DELETE = 本を廃棄する (削除)
├─ 図書館から本を取り除く
└─ リソースを削除

💡 主要なHTTPメソッド

GET - データ取得

用途: サーバーからリソースを取得

特徴:
├─ 安全(Safe): サーバーの状態を変更しない
├─ 等冪(Idempotent): 何度呼び出しても同じ結果
├─ キャッシュ可能
└─ ブラウザ履歴に残る

リクエスト例:
GET /api/users HTTP/1.1
Host: example.com
// JavaScript fetch API
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => console.log(data));

// jQuery
$.get('https://api.example.com/users', function(data) {
console.log(data);
});

// axios
axios.get('https://api.example.com/users')
.then(response => console.log(response.data));
# curl
curl https://api.example.com/users

# 特定のユーザー取得
curl https://api.example.com/users/123

# クエリパラメータの使用
curl "https://api.example.com/users?page=1&limit=10"

レスポンス例:

HTTP/1.1 200 OK
Content-Type: application/json

{
"users": [
{ "id": 1, "name": "田中太郎" },
{ "id": 2, "name": "山田花子" }
]
}

POST - データ作成

用途: サーバーに新しいリソースを作成

特徴:
├─ 安全ではない: サーバーの状態を変更
├─ 等冪ではない: 複数回呼び出すと複数のリソースを作成
├─ キャッシュ不可
└─ リクエストボディにデータを含む

リクエスト例:
POST /api/users HTTP/1.1
Host: example.com
Content-Type: application/json

{
"name": "田中太郎",
"email": "tanaka@example.com"
}
// fetch API
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: '田中太郎',
email: 'tanaka@example.com'
})
})
.then(response => response.json())
.then(data => console.log(data));

// axios
axios.post('https://api.example.com/users', {
name: '田中太郎',
email: 'tanaka@example.com'
})
.then(response => console.log(response.data));
# curl
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name":"田中太郎","email":"tanaka@example.com"}'

レスポンス例:

HTTP/1.1 201 Created
Location: /api/users/123
Content-Type: application/json

{
"id": 123,
"name": "田中太郎",
"email": "tanaka@example.com",
"createdAt": "2025-01-26T10:00:00Z"
}

PUT - 全データ更新

用途: リソースを新しいデータで完全に置き換える

特徴:
├─ 安全ではない: サーバーの状態を変更
├─ 等冪: 複数回呼び出しても結果が同じ
├─ リソース全体を置き換える
└─ 存在しない場合は作成することもある

リクエスト例:
PUT /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json

{
"name": "田中太郎",
"email": "newemail@example.com",
"phone": "090-1234-5678"
}
// fetch API
fetch('https://api.example.com/users/123', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: '田中太郎',
email: 'newemail@example.com',
phone: '090-1234-5678'
})
})
.then(response => response.json())
.then(data => console.log(data));

// axios
axios.put('https://api.example.com/users/123', {
name: '田中太郎',
email: 'newemail@example.com',
phone: '090-1234-5678'
})
.then(response => console.log(response.data));
# curl
curl -X PUT https://api.example.com/users/123 \
-H "Content-Type: application/json" \
-d '{"name":"田中太郎","email":"newemail@example.com","phone":"090-1234-5678"}'

PATCH - 部分データ更新

用途: リソースの一部のみを修正

特徴:
├─ 安全ではない: サーバーの状態を変更
├─ 等冪になる場合とならない場合がある
├─ 一部のフィールドのみ修正
└─ PUTより効率的

リクエスト例:
PATCH /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json

{
"email": "newemail@example.com"
}
// fetch API
fetch('https://api.example.com/users/123', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'newemail@example.com'
})
})
.then(response => response.json())
.then(data => console.log(data));

// axios
axios.patch('https://api.example.com/users/123', {
email: 'newemail@example.com'
})
.then(response => console.log(response.data));
# curl
curl -X PATCH https://api.example.com/users/123 \
-H "Content-Type: application/json" \
-d '{"email":"newemail@example.com"}'

PUT vs PATCH 比較:

既存データ:
{
"id": 123,
"name": "田中太郎",
"email": "old@example.com",
"phone": "090-1111-2222"
}

PUT リクエスト (全体置換):
{
"name": "田中太郎",
"email": "new@example.com"
}
結果:
{
"id": 123,
"name": "田中太郎",
"email": "new@example.com"
// phoneフィールドが消失!
}

PATCH リクエスト (部分更新):
{
"email": "new@example.com"
}
結果:
{
"id": 123,
"name": "田中太郎",
"email": "new@example.com",
"phone": "090-1111-2222"
// phoneフィールドが維持される!
}

DELETE - データ削除

用途: リソースを削除

特徴:
├─ 安全ではない: サーバーの状態を変更
├─ 等冪: 複数回削除しても結果が同じ
├─ レスポンスボディがない場合がある
└─ 復元不可能な場合がある

リクエスト例:
DELETE /api/users/123 HTTP/1.1
Host: example.com
// fetch API
fetch('https://api.example.com/users/123', {
method: 'DELETE'
})
.then(response => {
if (response.ok) {
console.log('削除完了');
}
});

// axios
axios.delete('https://api.example.com/users/123')
.then(response => console.log('削除完了'));
# curl
curl -X DELETE https://api.example.com/users/123

レスポンス例:

HTTP/1.1 204 No Content

または

HTTP/1.1 200 OK
Content-Type: application/json

{
"message": "ユーザーが削除されました",
"deletedId": 123
}

🔍 その他のHTTPメソッド

HEAD - ヘッダーのみ取得

用途: GETと同じだが、ボディなしでヘッダーのみ返す

使用例:
├─ リソースの存在確認
├─ ファイルサイズ確認
└─ 更新時間確認

例:
HEAD /api/users/123 HTTP/1.1
Host: example.com

レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 256
Last-Modified: Sat, 26 Jan 2025 10:00:00 GMT
# curl
curl -I https://api.example.com/users/123

OPTIONS - サポートメソッド確認

用途: サーバーがサポートするメソッドを確認 (CORSプリフライトリクエストで使用)

例:
OPTIONS /api/users HTTP/1.1
Host: example.com

レスポンス:
HTTP/1.1 200 OK
Allow: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Origin: *
# curl
curl -X OPTIONS https://api.example.com/users -i

📊 メソッド属性比較

┌─────────┬──────┬────────┬─────────┬────────────┐
│ メソッド │ 安全 │ 等冪性 │ キャッシュ可能 │ リクエストボディ │
├─────────┼──────┼────────┼─────────┼────────────┤
│ GET │ ✅ │ ✅ │ ✅ │ ❌ │
│ POST │ ❌ │ ❌ │ ❌ │ ✅ │
│ PUT │ ❌ │ ✅ │ ❌ │ ✅ │
│ PATCH │ ❌ │ △ │ ❌ │ ✅ │
│ DELETE │ ❌ │ ✅ │ ❌ │ △ │
│ HEAD │ ✅ │ ✅ │ ✅ │ ❌ │
│ OPTIONS │ ✅ │ ✅ │ ❌ │ ❌ │
└─────────┴──────┴────────┴─────────┴────────────┘

用語説明:
- 安全(Safe): サーバーの状態を変更しない
- 等冪(Idempotent): 複数回実行しても結果が同じ
- キャッシュ可能: レスポンスをキャッシュできる

💡 RESTful API設計

CRUDとHTTPメソッドのマッピング

Create  → POST
Read → GET
Update → PUT / PATCH
Delete → DELETE

RESTful APIの例

リソース: ユーザー(users)

GET /users - すべてのユーザー取得
GET /users/123 - 特定のユーザー取得
POST /users - 新規ユーザー作成
PUT /users/123 - ユーザー全体更新
PATCH /users/123 - ユーザー部分更新
DELETE /users/123 - ユーザー削除

入れ子リソース:
GET /users/123/posts - 特定ユーザーの投稿リスト
GET /users/123/posts/456 - 特定の投稿取得
POST /users/123/posts - 新規投稿作成
PUT /users/123/posts/456 - 投稿更新
DELETE /users/123/posts/456 - 投稿削除

実践例: ブログAPI

// ブログ投稿API

// 1. 投稿リスト取得 (ページング, フィルタリング)
GET /api/posts?page=1&limit=10&category=tech

// 2. 特定の投稿取得
GET /api/posts/123

// 3. 新規投稿作成
POST /api/posts
{
"title": "HTTPメソッドを完全に理解する",
"content": "...",
"category": "tech"
}

// 4. 投稿全体更新
PUT /api/posts/123
{
"title": "HTTPメソッドを完全に理解する (更新版)",
"content": "...",
"category": "tech"
}

// 5. 投稿部分更新 (閲覧数増加)
PATCH /api/posts/123
{
"views": 101
}

// 6. 投稿削除
DELETE /api/posts/123

// 7. コメント関連
GET /api/posts/123/comments - コメントリスト
POST /api/posts/123/comments - コメント作成
DELETE /api/posts/123/comments/456 - コメント削除

🤔 よくある質問

Q1. POSTとPUTの違いは?

答:

POST:
├─ 新しいリソース作成
├─ サーバーがリソースURIを決定
├─ 等冪ではない (複数回呼び出すと複数リソース作成)
└─ 例: POST /users

PUT:
├─ リソース全体置換
├─ クライアントがリソースURIを指定
├─ 等冪 (複数回呼び出しても結果同じ)
└─ 例: PUT /users/123

実践的な比喩:
POST = 「新しい口座を作ってください」(銀行が口座番号を割り当て)
PUT = 「123番の口座情報をこれに置き換えてください」

Q2. GETにボディを送れるか?

答:

技術的には可能ですが:
├─ HTTP仕様上は許可されるが推奨されない
├─ 多くのサーバー/フレームワークが無視する
├─ キャッシング、ログなどで予期せぬ動作
└─ クエリパラメータの使用を推奨

❌ 悪い例:
GET /api/users
{
"filters": { "age": 25 }
}

✅ 良い例:
GET /api/users?age=25

または複雑な検索はPOST使用:
POST /api/users/search
{
"filters": { "age": 25, "city": "東京" }
}

Q3. DELETEにボディを送れるか?

答:

可能だが注意が必要:
├─ HTTP仕様上は許可
├─ 一部のサーバー/プロキシが無視する可能性
├─ 通常はURIにリソースIDを含める
└─ ボディは追加情報の転送用

使用例:

✅ 一般的な方法:
DELETE /api/users/123

✅ 複雑な削除条件:
DELETE /api/posts/bulk
{
"ids": [1, 2, 3, 4, 5]
}

✅ 削除理由の伝達:
DELETE /api/users/123
{
"reason": "ユーザー要求",
"confirm": true
}

Q4. 等冪性が重要な理由は?

答:

等冪性の重要性:

1. ネットワーク障害への対応
├─ リクエスト失敗時に再試行可能
├─ 重複リクエストの心配なし
└─ 安全な再処理

例:
GET /users/123 → 何度呼び出しても安全
POST /users → 複数回呼び出すと複数ユーザー作成!
PUT /users/123 → 何度呼び出しても同じ結果
DELETE /users/123 → 何度削除しても同じ結果

2. クライアント再試行ロジック
├─ タイムアウト時に安全に再試行
└─ 自動再試行メカニズムの実装可能

3. キャッシングと最適化
├─ 等冪なリクエストはキャッシュ可能
└─ パフォーマンス最適化が容易

Q5. 実務でのメソッド選択基準は?

答:

選択ガイド:

1. データ取得のみの場合
→ GET

2. 新しいデータを作成する場合
→ POST

3. データを完全に置き換える場合
→ PUT
例: ユーザープロフィール全体更新

4. データの一部のみ修正する場合
→ PATCH
例: いいね数の増加、状態のみ変更

5. データを削除する場合
→ DELETE

6. 複雑な取得/検索の場合
→ POST /search
(GETのURL長さ制限を回避)

実践例:

// ✅ 良い例
GET /api/products - 商品リスト
GET /api/products/123 - 商品詳細
POST /api/products - 商品登録
PATCH /api/products/123/stock - 在庫のみ修正
PUT /api/products/123 - 商品情報全体更新
DELETE /api/products/123 - 商品削除

// ❌ 悪い例
GET /api/deleteProduct?id=123 - 削除はDELETEを使用
POST /api/getProducts - 取得はGETを使用
POST /api/updateProduct - 更新はPUT/PATCHを使用

🎓 実習してみましょう

1. fetch APIで練習

// GET リクエスト
async function getUser(id) {
const response = await fetch(`https://api.example.com/users/${id}`);
const data = await response.json();
return data;
}

// POST リクエスト
async function createUser(userData) {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
return await response.json();
}

// PUT リクエスト
async function updateUser(id, userData) {
const response = await fetch(`https://api.example.com/users/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
return await response.json();
}

// PATCH リクエスト
async function patchUser(id, partialData) {
const response = await fetch(`https://api.example.com/users/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(partialData)
});
return await response.json();
}

// DELETE リクエスト
async function deleteUser(id) {
const response = await fetch(`https://api.example.com/users/${id}`, {
method: 'DELETE'
});
return response.ok;
}

2. エラー処理を含む

async function apiRequest(url, options = {}) {
try {
const response = await fetch(url, options);

if (!response.ok) {
throw new Error(`HTTPエラー! ステータス: ${response.status}`);
}

return await response.json();
} catch (error) {
console.error('APIリクエスト失敗:', error);
throw error;
}
}

// 使用例
try {
const user = await apiRequest('https://api.example.com/users/123');
console.log(user);
} catch (error) {
console.error('ユーザー取得失敗');
}

🔗 関連文書

🎬 おわりに

HTTPメソッドはRESTful APIの核心です。各メソッドの特性を理解し、適切に使用すれば、直感的で保守性の高いAPIを設計できます!

次のステップ: HTTPステータスコードを読んで、200、404、500などのステータスコードを学びましょう。