REST APIにおける正しいHTTPメソッドの選択

  • 2017.11.26
  • Web
REST APIにおける正しいHTTPメソッドの選択

REST APIを設計する際の課題の1つは実行される操作に対応する適切なHTTPメソッド(GET、PUT、POSTなど)を選択することです。Web開発を始めたばかりの頃は「GETとPOSTだけで事足りるじゃん」と何も考えずにGET、POSTを乱用していましたが、最適化を意識しはじめるとそれが間違っていたことに気づきました。

WebリクエストはミドルウェアやOSといった多数のアプリケーションを通過するため、HTTP仕様で定義されている特性を理解して使い分ける必要があります。

HTTPメソッドの2つの重要な特性

HTTP仕様(RFC2616)では以下の2種類の特性が定義されています。

  • 安全なメソッド(Safe HTTP Methods)
    安全なメソッドは読み取り専用にすることによって実装者が意図しない動作をユーザーにさせないことである。
  • 冪等なメソッド(Idempotent HTTP Methods)
    冪等なメソッドはリクエストが1回であっても複数回であっても同じ結果を持つことを保証する。

原文からかなり端折りましたがだいたいこんな感じです。(原文で出てくる「副作用」っていうワードがいまいち理解できてないけど)

簡単な話HTTPメソッドの実装で迷ったら上記2つの特性を意識して選択すれば良いってことですね。以降はそれぞれのリクエストの特性について述べていきます

GET

GETリクエストは情報を取り出すために利用されるメソッドです。このメソッドは冪等かつ安全でなければならない為、GETを使って呼び出された操作はリソースの状態を変更してはいけません。

GET /books

特定の本を取得するためには

GET /books/<title>

POST

POSTリクエストは冪等ではないため、新しいリソースの作成や既存のリソースの更新に使用されます。たとえば、Studentという名前のリソースにname、college、major、gpaという属性があるとします。新しい生徒を登録するにはPOSTを使用して下記のように新しいリソースを作成します。

POST /students/ // Create a new student
{
  "name": "たけし",
  "college": "東京オタク大学",
  "major": "情報学"
}

POSTリクエストは部分的な更新も実行できます。たとえば、生徒のGPAを更新するにはstudent_idによって指定された特定のレコードに対してPOSTリクエストを行い、更新する属性のみを指定します。

POST /students/<student_id>
{
  "gpa": "3.9"
}

上記の例ではstudent_idが存在しない場合、アプリケーションは404エラーを返す必要があります。

PUT

PUTリクエストは冪等なので同一の要求を複数回繰り返すことができ、サーバー上のリソースの状態は最初の要求後にそれ以上変化しません。POSTと同様に新しいリソースを作成したり既存のリソースを更新したりすることができますが、部分的な属性を持つPOSTリクエストとは異なり、PUTリクエストは更新のためにリソースのすべての属性が含まれている必要があります。学生のGPAを更新するためのPUTリクエストは次のとおりです。

PUT /students/<student_id>
{
  "name": "たけし",
  "college": "東京オタク大学",
  "major": "情報学"
  "gpa": "3.9"
}

部分的な更新はリソースに多くの属性が含まれている場合特に重要です。差分を更新するためにGETを使用してリソースを最初に取得してからすべての属性を送信するのは無駄です。現実には多くの開発者がPEDで部分的な更新を許可していますが、これは冪等契約の違反です。部分的な更新の場合はPOSTを使用するか、後ほど説明するPATCHを使用するほうがいいでしょう。

DELETE

DELETEリクエストは冪等であり、リソースの削除に使用されます。多くの人が混乱するポイントとしてクライアントに返されるHTTPステータスコードの問題があります。例えば一度目のリクエストで削除に成功するとHTTP 200が返されますが、もう一度同じリクエストを行うとHTTP 404:Not Foundのような別のステータスコードを返すことになります。

冪等であるのになぜリクエスト回数によって違ったステータスコードが返ってくるのか。それは冪等であるべき対象がクライアントではなくサーバ上のリソースの状態であるからです。200が返ってくる場合や404の場合のどちらも、リソースは削除されサーバー側で状態は変更されません。レスポンス本文が空の場合はHTTP 204:No Contentを使用することもできます。

PATCH

PATCHリクエストはPUTと似ていますが冪等ではありません。よって以下のように部分的な更新に対して使用することができます。

PATCH /students/<student_id> //Partial update: OK
{
  "gpa": "3.85"
}

部分的な更新にPATCHを採用するか、POSTを使用するかは設計者次第です。

まとめ

ここまで述べた内容を要約した表は次のとおりです。

メソッド 性質 利用する場面
GET 冪等かつ安全 情報の取得
POST 冪等でも安全でもない リソースの作成または部分的な更新
PUT 冪等だが安全でない リソースの作成または完全な更新
DELETE 冪等だが安全でない リソースの削除
POST 冪等でも安全でもない 部分的な更新

「冪等性」と「安全性」を理解してHTTPメソッド最適な選択ができるように心掛けたいですね。