はじめに
HTTP API の開発における POST と PUT の使い分けは、言うまでもなくこんがらがりやすいところです。PUT メソッドをそもそも使っていない開発者も多いでしょう。しかし、使い分けをある程度理解することで、より表現力のある API 設計ができるようになります。
ここで POST と PUT の使い分けについて紹介します。
POST と PUT の違い
POST と PUT の根本的な違いは、リクエストに同封されているデータの 意図 です。POST は、リソースの新規作成、バッチ処理開始、データの削除など幅広く使うことができます。それに対して PUT は、使い方がもっと限定的で、主に既存リソースを「置き換える」ために使われます。
POST
POST リクエストを受付したサーバーは、送られたデータで 基本的になんでもしていい です。リソースを作成することも 201 (Created)
削除することも 204 (No Content)
非同期的処理を開始することも 202 (Accepted)
キャッシュを利用して既存リソースにリダイレクトすることも 303 (See Other)
幅広く使うことができます。そのため、基本的に冪等性がないオペレーションで、キャッシュの対象になりません。
POST メソッドは特に、リソースの新規作成 に使われることが多いです。RFC 7231 の仕様上、POST リクエストの結果、リソースが作成された場合、サーバーは Location
フィールドに新規リソースの識別子を記載した 201 (Created)
レスポンスを返すべきとされています。
# 新規 articles レコードを作成するリクエスト
POST /articles HTTP/1.1
{
"name": "Foo",
"author": "hankehly",
"content": "123"
}
# id=12 の articles レコードが作成されたことを伝えるレスポンス
HTTP/1.1 201 Created
Location: http://example.com/articles/12
新規リソースを作成する場合は、リクエスト送信時に識別子の id
が分かりません。このように、POST リクエストによるリソース作成は、RDB の INSERT
オペレーションと似ています。
PUT
PUT メソッドの意図は、対象リソースの 置き換え で、リクエスト送信時に識別子を指定する必要があることから、primary key を指定した INSERT ... ON CONFLICT DO UPDATE
文と似ています。
INSERT INTO articles
(id, name, author)
VALUES
(12, "test", "hankehly")
ON CONFLICT
(id)
DO UPDATE SET
name = "test",
author = "hankehly"
上記 SQL を PUT リクエストで表すと、以下のようになります。
PUT /articles/12 HTTP/1.1
{
"name": "test",
"author": "hankehly"
}
このように、PUT メソッドを使うことによって、サーバー側で保持している対象リソースのデータを リクエストの同封のデータで置き換える ように指示できます。同じ PUT リクエストを繰り返しても、対象リソースが置き換わるだけで、レスポンス内容もサーバー側のリソースの状態も変わらないため、冪等性のあるオペレーションです。
PUT の成功レスポンスには、いくつかのパターンがあります。
- 置き換え後のデータを
200 (OK)
で返す - 置き換え後のデータは返さないが、処理が成功したことを
204 (No Content)
で伝える - 対象リソースが存在しなかったため、新規作成したことを
201 (Created)
で伝える
HTTP/1.1 200 OK
{
"id": 12,
"name": "test",
"author": "hankehly"
}
終わりに
以上 POST と PUT の基本的な違いについて紹介しました。ぜひ、今後活用して、表現力の高い HTTP API の設計につなげていただければと思います。