この記事の最終更新日: 2026年5月28日

APIを作り始めたばかりの頃、よくある設計が 「とりあえずPOSTにしておく」 です。
たとえば、次のようなAPIです。
POST /getUsers
POST /createUser
POST /updateUser
POST /deleteUser
POST /searchUsers
一見すると、これでも動きます。
フロントエンドからリクエストを送れば、サーバー側で処理できます。
データ取得も、登録も、更新も、削除も、POSTで実装できます。
しかし、API設計としてはあまり良い形ではありません。
なぜなら、POSTだけでAPIを作ると、APIの意味がわかりにくくなり、保守性・安全性・拡張性に問題が出やすくなるからです。
この記事では、「とりあえずPOST」でAPIを作ると何がまずいのかを、具体例を使って解説します。
- そもそもPOSTとは何か?
- 「とりあえずPOST」のAPI例
- まずい理由1:APIの意図がわかりにくくなる
- まずい理由2:URLが動詞だらけになる
- まずい理由3:取得なのか更新なのか判別しにくい
- まずい理由4:キャッシュを活用しづらくなる
- まずい理由5:冪等性がわかりにくくなる
- まずい理由6:フロントエンド側の実装が読みにくくなる
- まずい理由7:API仕様書がわかりにくくなる
- まずい理由8:権限管理やログ分析がしにくくなる
- まずい理由9:REST APIの基本から外れる
- まずい理由10:後から設計を直しにくい
- 「とりあえずPOST」が許されるケースはある?
- POSTを使うべきか迷ったときの判断基準
- 悪い例と改善例
- さらに悪い例:1つのAPIで全部処理する
- 実務では「完全なREST」にこだわりすぎなくてもよい
- API設計で大切なのは一貫性
- まとめ
そもそもPOSTとは何か?
POSTは、HTTPメソッドの一つです。
主に、サーバーに対して 新しいデータを作成する ときに使われます。
たとえば、新しいユーザーを作成するAPIではPOSTを使います。
POST /users
リクエストボディは次のようになります。
{
"name": "山田太郎",
"email": "yamada@example.com"
}
このリクエストは、「新しいユーザーを作成してください」という意味です。
REST APIでは、HTTPメソッドごとに役割があります。
| メソッド | 主な役割 |
|---|---|
| GET | データを取得する |
| POST | データを作成する |
| PUT | データ全体を更新する |
| PATCH | データの一部を更新する |
| DELETE | データを削除する |
つまり、POSTは万能なメソッドではなく、基本的には「作成」に使うメソッドです。
「とりあえずPOST」のAPI例
初心者がAPIを作ると、次のような設計になりがちです。
POST /getUsers
POST /getUser
POST /createUser
POST /updateUser
POST /deleteUser
このような設計でも、サーバー側で処理を分岐すれば動きます。
たとえば、ユーザー一覧を取得するAPIでもPOSTを使えます。
POST /getUsers
ユーザー削除でもPOSTを使えます。
POST /deleteUser
しかし、この設計には問題があります。
それは、HTTPメソッドの意味を使えていない ことです。
REST APIらしく設計するなら、次のようになります。
GET /users
GET /users/1
POST /users
PUT /users/1
PATCH /users/1
DELETE /users/1
こちらの方が、APIの意味が明確です。
まずい理由1:APIの意図がわかりにくくなる
POSTだけでAPIを作ると、APIの意図がURL名に依存します。
たとえば、次のAPIを見てください。
POST /userAction
このAPIが何をするのか、すぐにはわかりません。
ユーザーを作るのか、更新するのか、削除するのか、検索するのか、URLだけでは判断しにくいです。
一方、REST APIらしく設計すると、HTTPメソッドとURLの組み合わせで意味がわかります。
GET /users
これは「ユーザー一覧を取得する」という意味です。
POST /users
これは「ユーザーを作成する」という意味です。
DELETE /users/1
これは「IDが1のユーザーを削除する」という意味です。
このように、HTTPメソッドを適切に使うと、APIの意図が自然に伝わります。
まずい理由2:URLが動詞だらけになる
「とりあえずPOST」でAPIを作ると、URLに動詞が増えます。
たとえば、次のようなURLです。
POST /getUsers
POST /createUser
POST /updateUser
POST /deleteUser
POST /searchUsers
POST /changePassword
POST /publishArticle
POST /cancelOrder
このように、処理ごとにURLを作っていくと、APIが増えるほど命名がバラバラになりやすいです。
REST APIでは、URLは基本的に リソースを表す名詞 にします。
たとえば、ユーザーなら /users、記事なら /articles、注文なら /orders です。
GET /users
POST /users
GET /users/1
PATCH /users/1
DELETE /users/1
URLは「何を扱うか」を表し、HTTPメソッドは「何をするか」を表します。
| 要素 | 役割 |
|---|---|
| URL | 対象のリソースを表す |
| HTTPメソッド | 操作内容を表す |
この役割分担ができていると、API全体が整理されます。
まずい理由3:取得なのか更新なのか判別しにくい
POSTは、サーバー側で何かしらの処理を行うメソッドです。
そのため、POSTだけでAPIを作ると、そのリクエストが安全な取得処理なのか、データを変更する処理なのかが見分けにくくなります。
たとえば、次のAPIがあります。
POST /users/search
これは検索APIかもしれません。
しかし、POSTなので、サーバー上のデータを変更する可能性もあります。
一方、次のようにGETで設計されていれば、基本的にはデータ取得だとわかります。
GET /users?keyword=山田
GETは、データを取得するためのメソッドです。
そのため、APIを利用する側は「このリクエストはデータを変更しない」と予測できます。
HTTPメソッドの意味が守られていると、APIの利用者が安心して使いやすくなります。
まずい理由4:キャッシュを活用しづらくなる
GETリクエストは、ブラウザやCDN、プロキシなどでキャッシュしやすいという特徴があります。
たとえば、次のAPIは商品一覧を取得するAPIです。
GET /products
このAPIのレスポンスは、条件によってはキャッシュできます。
[
{
"id": 1,
"name": "商品A",
"price": 1000
},
{
"id": 2,
"name": "商品B",
"price": 2000
}
]
もし商品一覧の取得をPOSTで作ってしまうと、キャッシュの仕組みを活かしにくくなります。
POST /getProducts
もちろん、POSTでも独自にキャッシュすることは不可能ではありません。
しかし、HTTPの標準的な性質としては、取得にはGETを使った方が自然です。
アクセス数が多いAPIでは、キャッシュできるかどうかがパフォーマンスに大きく影響します。
まずい理由5:冪等性がわかりにくくなる
API設計では、冪等性 も重要です。
冪等性とは、同じリクエストを何回実行しても、結果が同じになる性質のことです。
たとえば、次のDELETEリクエストを考えます。
DELETE /users/1
このリクエストは、「IDが1のユーザーを削除する」という意味です。
1回実行しても、2回実行しても、最終的に「ユーザー1が存在しない」という状態になります。
そのため、DELETEは冪等なメソッドとされています。
一方、POSTは基本的に冪等ではありません。
たとえば、次のリクエストを2回送ると、ユーザーが2人作成される可能性があります。
POST /users
{
"name": "山田太郎",
"email": "yamada@example.com"
}
POSTだけで更新や削除まで表現すると、「同じリクエストを再送してよいのか」がわかりにくくなります。
通信エラーやタイムアウトが発生したとき、クライアントがリトライしてよいか判断しづらくなるのです。
まずい理由6:フロントエンド側の実装が読みにくくなる
フロントエンド側でAPIを呼び出すコードも、POSTばかりだと意図が見えにくくなります。
たとえば、次のようなコードです。
await fetch('/getUsers', {
method: 'POST'
});
await fetch('/deleteUser', {
method: 'POST',
body: JSON.stringify({ id: 1 })
});
このようにURL名で操作を表現していると、API設計が処理名ベースになっていきます。
一方、HTTPメソッドを適切に使うと、コードからも操作内容が読み取りやすくなります。
await fetch('/users', {
method: 'GET'
});
await fetch('/users/1', {
method: 'DELETE'
});
こちらの方が、HTTPの意味とAPIの操作が一致しています。
フロントエンドとバックエンドの両方で、APIの意図を理解しやすくなります。
まずい理由7:API仕様書がわかりにくくなる
API仕様書を書くときも、POSTだらけのAPIは読みにくくなります。
たとえば、次のようなAPI一覧があるとします。
POST /getUsers
POST /getUserDetail
POST /createUser
POST /updateUser
POST /deleteUser
POST /searchUser
POST /activateUser
POST /deactivateUser
すべてPOSTなので、HTTPメソッドから操作内容を判断できません。
URL名を読まないと、何をするAPIなのかわかりません。
REST APIらしく設計すると、一覧したときに構造が見えやすくなります。
GET /users
GET /users/{id}
POST /users
PUT /users/{id}
PATCH /users/{id}
DELETE /users/{id}
PATCH /users/{id}/activation
同じ /users というリソースに対して、取得・作成・更新・削除が整理されています。
API仕様書は、バックエンドだけでなく、フロントエンド、アプリ開発者、QA、外部連携先なども読む可能性があります。
そのため、見ただけで意図が伝わる設計が重要です。
まずい理由8:権限管理やログ分析がしにくくなる
HTTPメソッドを適切に使っていると、ログや権限管理でも意味を読み取りやすくなります。
たとえば、アクセスログに次のような記録があるとします。
GET /users/1
DELETE /users/1
PATCH /users/1
この場合、ログを見れば「取得」「削除」「一部更新」がすぐにわかります。
一方、すべてPOSTだと、ログだけでは操作内容が見えにくくなります。
POST /user
POST /user
POST /user
もちろん、リクエストボディまで見れば判断できるかもしれません。
しかし、ログ分析や監視、アラート設計では、HTTPメソッドとURLだけで概要がわかる方が便利です。
たとえば、削除系APIの呼び出しだけを監視したい場合も、DELETEを使っていれば検出しやすくなります。
まずい理由9:REST APIの基本から外れる
REST APIでは、リソースに対してHTTPメソッドで操作を表現します。
たとえば、ユーザーというリソースに対しては、次のように設計します。
GET /users
POST /users
GET /users/1
PUT /users/1
PATCH /users/1
DELETE /users/1
この設計では、URLはリソースを表し、HTTPメソッドは操作を表します。
一方、「とりあえずPOST」のAPIは、処理名をURLに書くRPC風の設計になりやすいです。
POST /createUser
POST /updateUser
POST /deleteUser
RPC風のAPIが絶対に悪いわけではありません。
ただし、REST APIとして作るなら、HTTPメソッドとリソース設計を意識した方が自然です。
まずい理由10:後から設計を直しにくい
最初は小さなAPIでも、機能が増えるとエンドポイントはどんどん増えていきます。
最初に「とりあえずPOST」で作ってしまうと、後からREST APIらしく整理するのが大変になります。
たとえば、最初は次のようなAPIだけだったとします。
POST /getUsers
POST /createUser
しかし、あとから機能が増えていきます。
POST /getUserDetail
POST /updateUser
POST /deleteUser
POST /searchUsers
POST /activateUser
POST /deactivateUser
POST /changeUserEmail
POST /resetUserPassword
この段階になってからREST APIらしく整理しようとすると、フロントエンド側の修正も必要になります。
既存のクライアントが使っているAPIを変える場合は、互換性も考えなければいけません。
APIは一度使われ始めると、簡単には変更できません。
そのため、最初からある程度整理された設計にしておくことが大切です。
「とりあえずPOST」が許されるケースはある?
ここまでPOSTだけでAPIを作る問題を説明してきましたが、POSTを使うべきケースもあります。
たとえば、次のような場合です。
データを作成する場合
新しいユーザーや記事、注文を作成する場合はPOSTが自然です。
POST /users
POST /articles
POST /orders
複雑な検索条件を送る場合
検索は基本的にGETで表現できます。
GET /users?keyword=山田&status=active
ただし、検索条件が非常に複雑で、クエリパラメータだけでは表現しづらい場合は、POSTを使うこともあります。
POST /users/search
{
"keyword": "山田",
"status": ["active", "pending"],
"created_at": {
"from": "2026-01-01",
"to": "2026-12-31"
},
"sort": [
{
"field": "created_at",
"order": "desc"
}
]
}
このような場合、POSTを使う判断は実務上ありえます。
ただし、「検索だから必ずPOST」ではなく、まずGETで表現できるかを考えるのが基本です。
特定のアクションを実行する場合
REST APIでは表現しにくい業務アクションもあります。
たとえば、次のような操作です。
POST /orders/1/cancel
POST /articles/1/publish
POST /invoices/1/send
注文をキャンセルする、記事を公開する、請求書を送信する、といった操作は、単純なCRUDでは表現しにくいことがあります。
このような場合は、POSTでアクションを表現する設計もあります。
ただし、状態変更だけで表せるならPATCHを使うこともできます。
PATCH /orders/1
{
"status": "cancelled"
}
どちらがよいかは、業務上の意味によります。
単にステータスを変えるだけならPATCH、キャンセル処理として在庫戻し・通知送信・決済取消など複数の副作用があるなら POST /orders/1/cancel のような設計も検討できます。
POSTを使うべきか迷ったときの判断基準
HTTPメソッドで迷ったら、次のように考えると判断しやすいです。
| やりたいこと | メソッド |
|---|---|
| データを取得したい | GET |
| 新しいデータを作りたい | POST |
| データ全体を置き換えたい | PUT |
| データの一部を変更したい | PATCH |
| データを削除したい | DELETE |
もう少し具体的にすると、次のようになります。
GET /users
ユーザー一覧を取得する。
POST /users
新しいユーザーを作成する。
PUT /users/1
IDが1のユーザー情報を全体更新する。
PATCH /users/1
IDが1のユーザー情報の一部を更新する。
DELETE /users/1
IDが1のユーザーを削除する。
この基本に当てはめても表現しづらい場合に、POSTでアクションを表現するか検討するとよいです。
悪い例と改善例
悪い例:全部POST
POST /getUsers
POST /getUser
POST /createUser
POST /updateUser
POST /deleteUser
この設計では、HTTPメソッドの意味を活かせていません。
改善例:HTTPメソッドで操作を表す
GET /users
GET /users/1
POST /users
PUT /users/1
PATCH /users/1
DELETE /users/1
この設計では、ユーザーというリソースに対する操作が整理されています。
さらに悪い例:1つのAPIで全部処理する
次のようなAPIも避けた方がよいです。
POST /api
{
"action": "deleteUser",
"id": 1
}
または、次のような形式です。
POST /user
{
"mode": "delete",
"user_id": 1
}
この設計では、URLとHTTPメソッドを見ても何をするAPIなのかわかりません。
処理内容がすべてリクエストボディの中に隠れてしまっています。
このようなAPIは、次のような問題を起こしやすいです。
- API仕様書が読みにくい
- ログから操作内容を追いにくい
- 権限管理が複雑になる
- テストケースが整理しにくい
- フロントエンド側の実装が属人的になる
特殊な事情がない限り、APIはリソースごとに分けた方が扱いやすくなります。
実務では「完全なREST」にこだわりすぎなくてもよい
ここまでREST APIらしい設計を説明しましたが、実務では必ずしも完璧なRESTを目指す必要はありません。
大事なのは、API利用者にとってわかりやすく、一貫性があり、安全に使えること です。
たとえば、業務アクションによっては次のようなAPIも現実的です。
POST /orders/1/cancel
POST /users/1/send-password-reset-email
POST /reports/export
これらは純粋なCRUDではありません。
しかし、業務上の意図が明確で、チーム内でルールが統一されていれば、実務では十分に使いやすい設計です。
避けるべきなのは、何のルールもなく、すべてをPOSTで処理することです。
API設計で大切なのは一貫性
API設計では、一貫性がとても重要です。
たとえば、ある画面では削除にDELETEを使っているのに、別の画面ではPOSTを使っていると、利用者は混乱します。
DELETE /users/1
POST /deleteArticle
このように設計が混ざると、API全体の見通しが悪くなります。
チームで次のようなルールを決めておくとよいです。
取得はGET
作成はPOST
全体更新はPUT
部分更新はPATCH
削除はDELETE
複雑な業務アクションはPOSTを検討
URLは基本的に名詞にする
このようなルールがあるだけで、API設計のブレをかなり減らせます。
まとめ
「とりあえずPOST」でAPIを作ると、最初は楽に感じます。
しかし、APIが増えてくると、次のような問題が出やすくなります。
| 問題 | 内容 |
|---|---|
| 意図がわかりにくい | 取得・作成・更新・削除の区別が見えにくい |
| URLが動詞だらけになる | /getUsers や /deleteUser が増える |
| キャッシュしづらい | GETの性質を活かせない |
| 冪等性がわかりにくい | リトライしてよいか判断しづらい |
| 仕様書が読みにくい | すべてPOSTで操作内容が見えない |
| ログ分析しにくい | メソッドから操作を判断できない |
| 後から直しにくい | 既存クライアントとの互換性問題が出る |
POSTは便利なメソッドですが、何でもPOSTにすればよいわけではありません。
基本的には、次のように使い分けましょう。
GET /users ユーザー一覧を取得
GET /users/1 特定のユーザーを取得
POST /users ユーザーを作成
PUT /users/1 ユーザー全体を更新
PATCH /users/1 ユーザーの一部を更新
DELETE /users/1 ユーザーを削除
APIは、サーバー側だけでなく、フロントエンドや外部システムからも利用される「契約」です。
だからこそ、「動けばよい」ではなく、意味が伝わる設計にすることが大切です。
REST APIを作るときは、「とりあえずPOST」ではなく、HTTPメソッドの役割に合わせて設計するようにしましょう。

大阪のエンジニアが書いているブログ。



コメント