はじめに
業務でREST APIを使用したWebシステムの開発に携わっている。基本的な技術は業務の中で磨かれるが、そもそもREST APIとは何なのか、どのような考えのもとそのシステムが構成されているのか知りたいと思い、調べていく中で得た知見をまとめる。
目次
1. Webシステムの全体像
2. Webの技術
3. RESTの制約とは
① クライアント / サーバ
② ステートレス
③ キャッシュ可能性
④ 階層化システム
⑤ コードオンデマンド
⑥ 統一性インタフェース
(1) HTTPメソッド
(2) URI
(3) ステータスコード
1. Webシステムの全体像
まず、Webシステムがどのような構成になっているのか、代表的な構成例を用いて考えてみます。
システムは大まかにブラウザとサーバ群に分けて考えることができます。
ユーザは、パソコンやスマートフォンといったデバイス上でブラウザを操作します。
ブラウザはサーバに接続し、サーバはデータベースから必要な情報を取得したり、登録したりします。
APサーバ:アプリケーションサーバの略。
DB:データベースの略。
- ブラウザ:ユーザインタフェースを提供
- Webサーバ:HTTP通信の受付や静的コンテンツの配信
- APサーバ:業務ロジックなどを実行
- DB:データを永続的に保存
これを、ECサイトで商品を検索した場面を例にして考えてみると
- ブラウザ:ユーザが商品を検索する
- Webサーバ:商品の検索をブラウザから受け付け、APサーバに該当する商品を探すように依頼する
- APサーバ:検索条件をもとにDBへ問い合わせ、該当する商品情報を探す
- DB:商品情報を保持する倉庫であり、APサーバからの要求に応じて必要な商品情報を返却する
となります。
ここで重要なのは、
Webシステムは1台のコンピュータですべての処理をするのではなく、ネットワークを介して複数のコンポーネントで役割を分散させて1つの機能を実現している
ということです。
これを分散システムと呼びます。
2. Webの技術
Webは
- URIによって情報を識別する
- HTTPによって通信する
- HTMLなどによって情報を表現する
- ハイパーリンクによって情報同士を関連付ける
といった仕組みを組み合わせたネットワーク上の情報システムです。
そして、このWebを支えている主要な技術がHTTP(Hypertext Transfer Protocol)です。このHTTPを利用して、クライアントとサーバでメッセージのやり取りを行います。
3. RESTの制約とは
前述したように、WebはHTTP/HTTPSの技術を使用しており、この技術を使ったAPI(Application Programming Interface)をWeb APIと呼びます。
Web APIの中で、現在主流となっているのがREST APIです。
REST APIのRESTとは、「Representational State Transfer」の略です。特定の技術スタックやフレームワークがあるのではなく、
ネットワークベースのアーキテクチャスタイルです。これをHTTPで実現したのが、REST APIです。
つまり、HTTPを使ったAPI(web API)をどう使用するかの設計ルールの集合体です。
以下の6つがこの設計ルールに当てはまります。
- クライアント/サーバ
- ステートレス
- キャッシュ可能
- 階層化システム
- インタフェース統一性
- コードオンデマンド
また、これらをまとめてRESTの制約と呼びます。
① クライアント / サーバ
Webは単一のコンピュータで全ての処理を行うのではなく、複数のコンピュータで処理を分散させる分散システムの構造をしています。特にクライアントとサーバに分離して処理を行う構成を、クライアント/サーバといいます。
クライアントがUI(ユーザインタフェース)の役割を果たし、サーバがデータ処理やストレージとしての役割を果たします。
② ステートレス
ステートレスとは、サーバがクライアントのアプリケーション状態(ステート)を保持しないということです。この対義語として、サーバがアプリケーション状態を保持するステートフルというものがあります。この2つの違いについて、例を用いて考えてみましょう。
以下が処理の流れです。
- 銀行サイトにログイン
- 振込画面から振込先口座を入力
- 振込金額を入力
- 振込実行ボタンを押下
この処理をステートフルなシステムで実現したものが以下の図です。
こちらでは、ログイン情報・振込先口座・振込金額をそれぞれ別のリクエストで送信しています。
前のリクエストで送った内容はサーバ側で保持しているため、後続のリクエストでは新しく追加された情報を送るだけで処理を進めることができます。

次に、ステートレスで実現されたシステムについて見てみましょう。
こちらでは、ステートフルなシステムとは違い、前のリクエストで受け取った情報をサーバは保持していません。 そのため、過去のリクエストで送信済みの内容であっても、処理に必要な情報はリクエストごとにサーバへ送らなければなりません。
例えば、最後の振込実行リクエストでは、
・ログイン情報
・振込先口座
・振込金額
といった必要な情報全てサーバに送信しています。
データ送信量だけを見ると、ステートフルな設計の方が送信量が少ないため良いように見えますが、ステートレスにはリクエストごとにサーバを分散させやすいというメリットがあります。
例えば、ステートフルなシステムで「振込金額入力」のリクエストだけが別のサーバへ送られた場合、そのサーバは過去のリクエスト内容を保持していないため、
振込金額は分かったが、誰からの振込みだろう?それに、振込先口座はどこだろう?
という状態になってしまいます。
一方、ステートレスなシステムでは、各リクエストに必要な情報がすべて含まれています。そのため、他のサーバがリクエストを受け取っても同じように処理できるようになります。
このように、ステートレスな設計は負荷分散やサーバの増減との相性が良く、大規模なWebシステムやREST APIで広く採用されています。
③ キャッシュ可能性
キャッシュとは、1度取得したAPIの結果を保持しておき、再度同じAPIが呼ばれたときに、そのデータを再利用する仕組みを指します。
クライアントがそのレスポンスをキャッシュし、再利用できるかどうか示すことをキャッシュ可能性と言います。この仕組みにより、2回目以降はWebサーバにアクセスする必要がない場合もあり、データ量と呼び出し回数を減らすことでネットワークを最適化することが出来ます。キャッシュを使用するときはどれくらいの期間キャッシュを保持するのか指定します。
④ 階層化システム
階層化システムとは、各コンポーネントが直接接続する相手だけを意識し、それより先の層を意識せずに構築できる仕組みです。
例えば、クライアントとWebサーバの間にプロキシサーバを設置したとしても、問題なくシステムを稼働させることができます。なぜなら、クライアントから見て、通信先がWebサーバであってもプロキシサーバであっても、その先の構成を意識する必要がないためです。
また、Webサーバの先にあるAPサーバが1台から2台に増えたとしても、クライアントとWebサーバの接続方法は変わらないため、クライアント側への影響はありません。階層化システムには、直接接続できる直近のレイヤーより先を意識しない制約があります。
・webサーバからプロキシサーバへとクライアントからの接続先が変化したことを表している。プロキシサーバに変化したとしても、クライアントとサーバの階層ではHTTP通信でやり取りを行うというルールは変わらないため、大胆に設計を変える必要がありません。

・webサーバの先にあるAPサーバが1台か2台であろうと、クライアント側からは隠されているため、赤枠のクライアントとwebサーバの接続方法は変わらず、何も影響がありません。

⑤ コードオンデマンド
コードオンデマンドとは、JavaScriptなどのコードをサーバからダウンロードして、クライアント側で実行することです。これにより、クライアント側にあらかじめすべての処理を実装しておく必要がなくなります。
このコードオンデマンドは6つの制約のうち、唯一の任意となっています。コードオンデマンドはクライアントで実行するため、プロキシや監視システムからどんな処理になっているのか把握することが難しくなる場合もあります。システムの可視性を低下させてしまう恐れがあることから、任意の制約となっています。
⑥ 統一性インタフェース
APIの操作を決められた方法に則って設計する制約です。決められた操作方法を用いることで、サーバ側の実装が変わった場合でもクライアント側への影響を小さくできます。また、Webブラウザやスマホアプリ、APIクライアントなど、多様なクライアントから利用しやすくなるため、再利用性や拡張性を高められます。
そのルールの具体例として、主に以下のようなものがあります。
- HTTPメソッド
- URI
- ステータスコード
(1) HTTPメソッド
HTTPメソッドとは、「何をしたいのか」を表現するために使用します。
HTTPメソッドは全部で8つあります。
実際のシステムでよく見られるのは上の4つです。
| メソッド | 意味 |
|---|---|
| GET | リソースの取得 |
| POST | リソースへのデータ追加など |
| PUT | リソースの更新 |
| DELETE | リソースの削除 |
| HEAD | リソースのヘッダ(メタデータ)の取得 |
| OPTIONS | リソースがサポートしているメソッドの取得 |
| TRACE | HTTPレスポンスにリクエストの内容をそのまま返却する※デバッグ用 |
| CONNECT | プロキシサーバに接続を依頼 |
GET /users/123
上記のようなリクエストがあった時に、このリクエストはデータを取得するためのリクエストであるということが分かります。
(2) URI
「対象のリソース」を表現するために使用します。
例えば、
/usersを"ユーザというリソースの集合"を表すURIとして設計すると、URIから対象となるリソースを読み取ることができます。
・パスパラメータ
特定のリソースを指定するために使用します。
パスパラメータは以下のようなテンプレートで表現します。
users/{userId}
{}で囲まれた箇所に値を埋め込みます。上記の例では、userIdの部分にどのような値が入ったかで、対象リソースを判断することができます。
例えば、「users/123」というURIではIDが123のユーザを表現していることが読み取れます。
・クエリパラメータ
リソースに対して検索条件や並び順、ページ番号など追加の情報を指定するために使用します。
users?sort=age
?の後ろにキーと値のペアを埋め込むことで条件を指定します。
上記の例では、ユーザ一覧を年齢順で並び替えるという条件が課されていることが読み取れます。
(3) ステータスコード
上記の2つはリクエストの時に表現するものでした。それに対して、このステータスコードはリクエストの結果を表現するものです。
ステータスコードは3桁の数字で表現され、先頭の数字によって以下の5つに分類することが出来ます。
| コード | 意味 |
|---|---|
| 1xx | 処理中 |
| 2xx | リクエストが成功 |
| 3xx | 他のリソースへリダイレクトなど |
| 4xx | クライアントのリクエストが原因によるエラー |
| 5xx | サーバが原因によるエラー |