「とりあえずPOST」でAPIを作ると何がまずいのか

ITインフラ
この記事は約15分で読めます。

この記事の最終更新日: 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は、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メソッドの役割に合わせて設計するようにしましょう。

コメント

タイトルとURLをコピーしました