こんにちは。バックエンド担当の谷口です。
みなさまは Web API を設計するとき、どのようなことを考えていますか?一度、API を公開し開発が進むと、そこからのインターフェースの変更は容易には出来ません。開発を円滑に進めるためにも、よく知られている思想に則って設計したいものです。この記事では、Web API の分野で最も浸透しているであろう設計原則の REST を紹介します。
この記事は「Web エンジニアなら知っておきたい」シリーズの 3 回目の投稿です。
前回の記事はこちら。 engineers.fenrir-inc.com
REST とは?
REST は、Representational State Transfer の頭文字をとった言葉で、複数のソフトウェアを連携させるのに適した制約条件であり、Web API の定義に使用される共通仕様の 1 つです。REST は、Roy Fielding さんによって 2000 年に論文で初めて定義されました。REST そのものは適用範囲の広い抽象的な概念モデルですが、REST の考え方を Web API に適用したものを REST API (RESTful API) と呼びます。それでは、REST が示す設計原則を見てみましょう。
REST の設計原則
REST の原則は、主に 4 つに分類できます。*1
原則 1: ステートレスなクライアント/サーバ
クライアント/サーバとは、クライアントとサーバを分離し、ネットワーク通信によって接続するソフトウェアモデルで、それぞれを個別に拡張させていくという考え方です。つまり、サーバのアプリケーションに影響を与えることなく、クライアントを変更できるようにします。また、その逆も然りです。問題の分離ができるため、互いに独立した拡張が可能になります。問題が起きた時でも迅速に発見でき、高頻度なアップデートを実現できるため、結果としてビジネスの成長をサポートすることに繋がります。
そして、クライアントとサーバ間のネットワーク通信はステートレスです。つまり、サーバはクライアントの状態を管理しません。クライアントは必要な情報を都度送る必要がありますが、サーバは状態を管理する必要がなくなる分シンプルで拡張性のあるシステムを構築できるようになります。
原則 2: リソースを一意な URI で識別できる
REST を考慮したシステムでは全てのリソースが URI で表現される一意なアドレスを持ちます。
下記の URI を見てください。
GET https://coffee-host/coffee-beans
これは架空のコーヒー豆販売サイトの URI ですが、実行せずともコーヒー豆の一覧情報を取得することが予想できると思います。クライアントや開発者は URI を一目見ればなんの情報を表しているのかを理解できるため、API の利用やメンテナンスがしやすくなります。そして、リソースに対する操作が一貫性を持ち、予測可能な動作をする API を提供できるため、開発者はより信頼できるシステムを構築することに繋がります。
原則 3: HTTP のメソッドにより操作を表現した統一インターフェース
統一インターフェースとは、リソースを操作する命令体系が予め定義され、共有されていることを指します。インターフェースが統一されていれば、Web やモバイルなどの別々のクライアントからでも同じ方法でサーバとやり取りをすることができます。
Web API であれば、GET
POST
などの HTTP メソッドを使用して、クライアントとサーバ間でのリソースの操作を行いましょうということになります。例えば、原則 2 で登場した coffee-beans リソースを取得する場合を考えてみましょう。GET
メソッドを使用して一覧を取得したいのであればリソース名を使用して /coffee-beans
、詳細を取得したいのであればリソース名と識別子を組み合わせて /coffee-beans/{coffeeBeanId}
と記述し取得することが望ましいです。一方で、動詞の get
を使用して、/get-coffee-beans-list
や /get-coffee-beans-detail
のように記述するのは良くない例です。操作や状態などを表す言葉を組み合わせてしまうと、開発者ごとにインターフェースがバラバラになり、分かりづらく余計な工数がかかってしまいます。
リソース名に対して HTTP メソッドや識別子などを上手に組み合わせて操作することで、統一されたインターフェースが保証されるのです。
利用可能な HTTP メソッドは 9 種類もありますが、以下の 4 つ(CRUD 操作)を主に使用してリソースを操作します。
GET: リソースの取得 POST: リソースの作成 PUT: リソースの更新 DELETE: リソースの削除
原則 4: リソース間の接続性
リソースを様々な形式(HTML, JSON, XML, YAMLなど)で表現できるようにし、リソースに含まれるリンクを元に別のリソースへ接続したり、遷移したりできるようにします。
架空のコーヒー豆販売サイトの API レスポンス(JSON)を例にとって見てみましょう。
// GET /coffee-beans/{coffeeBeanId} // coffee-beans リソースの詳細情報 { ..., "country": "Brazil", "roast": "city", "shop": { "name": "谷口珈琲", "link": "https://coffee-host/shops/{shopId}", ..., }, ..., }
coffee-beans リソースを見ると、産地や焙煎度合いなどのコーヒー豆に対する情報だけでなく、販売店情報の shop も返却されており、link
から shops
リソースの情報を取得できるようになっています。Web API の設計をする際に、リソース同士が適切に接続されるように考えることは重要です。この考え方により、リンクを辿るだけで別のリソースにアクセスできるため、使いやすい API になります。
REST API の勘所
ここでは REST API を設計する際に、さらに押さえておきたい観点を 3 つ紹介します。
HTTP メソッドの冪等性と安全性
REST API を設計する際には、HTTP メソッドの適切な選択が重要になります。特に、冪等性(Idempotence)と安全性(Safety)は正しくメソッドを選択することにおいて重要な概念です。ここでは、冪等性と安全性について見てみましょう。
冪等性とは
冪等性は、ある操作を複数回実行しても、最初の 1 回目と同じ結果が得られる特性を指します。例えば、GET
メソッドは冪等性があります。同じリソースに対して何度も GET
リクエストを送信したとしても、リソースの状態は変化しません。しかし、POST
メソッドは通常冪等性がありません。同じリクエストを N 回送信すると、N 個の新しいリソースを作成する可能性があるためです。そして、 POST
メソッドと混同しそうになりますが、 PUT
メソッドには冪等性があります。PUT
メソッドは、指定した URI に新しいデータを作成するか、既存のデータを更新します。もし、同じリクエストを複数回送信しても、リソースは一貫して同じ状態となります。つまり、PUT
メソッドを使用する際は、冪等を意識して実装する必要があります。
冪等性を考慮することで、ネットワークの問題やエラーが発生してリトライの処理が発生したとしても、システムは一貫して安定した状態を維持できるようになります。
安全性とは
安全性は、リクエストがリソースの状態を変更しない特性を指します。例えば、GET
メソッドはリソースの状態を変更せず取得のみを行うため安全です。一方で、PUT
メソッドは指定した URI に新しいデータを作成するか、既存のデータを更新します。よって、PUT
メソッドはリソースの変更を伴うため安全ではありません。つまり、PUT
メソッドは「冪等であるが、安全でない」メソッドになります。
安全性を考慮することで、クライアントがリソースの読み取り操作を行うか、リソースの変更を行うかを適切に判断しながら開発を進めることができます。
適切な HTTP メソッドの選択
以下に、一般的な HTTP メソッドの冪等性と安全性について示します。
HEAD 冪等性 ○ 安全性 ○ GET 冪等性 ○ 安全性 ○ POST 冪等性 × 安全性 × PUT 冪等性 ○ 安全性 × PATCH 冪等性 △ 安全性 × DELETE 冪等性 ○ 安全性 × CONNECT 冪等性 × 安全性 × OPTIONS 冪等性 ○ 安全性 ○ TRACE 冪等性 ○ 安全性 ○
PATCH
メソッドの冪等性が △ の理由は、リソースをどの範囲で更新するかによって冪等かどうかが変わるためです。PUT
メソッドのようにリソース全体をリクエストする場合は冪等となります。しかし、PATCH
メソッドは基本的に既存のリソースを部分的に更新するために使用します。例えば、部分的な更新で N 回の PATCH
リクエストを繰り返している間に、別の部分が更新されてしまうとその前後で非冪等となります。
クライアントやサーバは HTTP メソッドの性質に応じたリクエスト/レスポンスを実装することで、一貫性を持ち、予測可能で安全に API を使用できるようになります。
バージョニング
完璧に設計できたと思っていても、ビジネスの成長に伴って API に変更を加えなければいけないことが出てくると思います。そんな時に、継続的に拡張していく方法を紹介します。それは、API はバージョン管理をしましょうということです。
バージョン管理をすることで開発速度を早められますし、メジャーアップデートがある場合に、過去バージョンと共存させることもできます。API を廃止したい時は、移行期間を十分に確保して、利用者に周知をし、API の全ての呼び出し元を新バージョンに移行し、過去バージョンの API を削除します。
例えば、以下に示すように URI にバージョンを含めてみましょう。
https://coffee-host/v1/coffee-beans/{coffeeBeanId}
バージョン番号は、バージョンであることを分かりやすくするために、v1
v2
などにすると良いと思います。
キャッシュ
REST API の呼び出しは、ステートレスでリソースを取得するのに必要な情報を都度送る必要がありコストがかかります。よって、API のレスポンスをキャッシュし、API の呼び出し回数を減らしたり、通信時間を短縮したりすることによってパフォーマンスの向上が期待できます。よく使われるキャッシュのパターンを紹介します。
Cache-Aside パターン
① クライアントからサーバへリクエストする ② データがキャッシュに存在するかを確認する ③ 存在した場合、キャッシュからデータを取得し返却する ④ 存在しなかった場合、データベースにアクセスしてデータを取得する ⑤ 取得したデータをキャッシュに保存する
その他の設計パターン
REST 以外にも API の設計パターンはありますので、気になる方は以下を参照ください。
おわりに
今回は、REST を紹介しました。必ず全ての原則を満たす必要があるわけではないですが、REST を意識した Web API を設計できれば得られる恩恵はたくさんありますので、ビジネスの成長を加速させるためにも検討いただけますと幸いです。
次回の「Web エンジニアなら知っておきたい」シリーズもお楽しみに。
参考
- Architectural Styles and the Design of Network-based Software Architectures
- Best Practices for Designing a Pragmatic RESTful API
- 『REST API』とは
- 【図解】RESTful API とは何なのか【2023年版】
- HTTP リクエストメソッド
- Cache-Aside
- Webアプリケーションにおける正しいキャッシュ戦略
- Safe (安全) (HTTP メソッド)
- Idempotent (べき等)
- 冪等と安全に関する誤解
*1:論文では実は原則という言葉を使っておらず、「REST のアーキテクチャを導き出したプロセス」という言葉で 6 つ挙げられています。それらを、Web API にフィットさせ整理した 4 つが原則として世に出ているようでした。とはいえ、ここで紹介する 4 つの原則と論文で言及されている 6 つのプロセスは重なるところも非常に多いです。このセクションで紹介できていないキャッシュの項目は REST API の勘所として紹介しています。
https://xtech.nikkei.com/atcl/nxt/column/18/00138/092100882/