先月、Skillsmatterの「Fast Track to RESTful Microservices」トレーニングに出席しました。このトレーニングでは、REST APIがWebアプリケーションや特にマイクロサービスにおいて実現できることを探求しました。個人としてのこのトレーニングでの最大の収穫は、RESTの真意について、さらにRESTに関する長所と短所について理解が深まったことです。
これまで私は主にモバイルテクノロジーに打ち込んできたため、WebAPIの「使う側」に身を置いてきたことになります。これまで使ってきたAPIの大半は「RESTful」であったと考えていましたが、RESTfulがどんなものかをよりよく理解したいま、それらの99%はRESTfulとは程遠いものであったと言えます(サーバーサイドでなにかが加えられたためクライアントが破損する、という話は、聞き覚えがありますよね?)。
定義
「REST」という用語は、「REpresentational State Transfer」を表します。次のような正式な定義があります。
アプリケーションの状態を進行させる手段としての、状態の表現(ドキュメント)のクライアント/サーバー間の転送をベースとした、APIのアーキテクチャスタイル
制限事項
アプリケーションがRESTfulとみなされるには、RESTに関する以下の制限事項を満たす必要があります。制限事項の順守によって、パフォーマンス、スケーラビリティ、簡潔性、拡張性、可視性、移植性、信頼性などの望ましい非機能特性を持った分散型ハイパーメディアシステムを実現できます。
- クライアント/サーバー
- クライアントサーバーモデルでは、「関心の分離(SoC)」によってクライアントをデータストレージに関係しないようにすることが望まれます。これにより、クライアントコードの移植性が改善されます。一方、サーバーがユーザーインターフェイスやユーザーの状態に関与しないことによって、サーバーの簡潔性とスケーラビリティが向上します。定義された制限事項を満たすかぎり、サーバーとクライアントをそれぞれ単独で開発できます。
- ステートレス
- リクエストがやり取りされる間、クライアントのコンテキストはまったくサーバーに保持されません。各リクエストは、必要な情報をすべて含んでいなければなりません。ステートレスなサーバーでは、リソースをすばやく解放できるのでスケーラビリティが向上し、実装も簡単になります。信頼性によって、部分的な故障からのリカバリーが容易になります。可視性の点では、監視システムは単一のリクエストを調べるだけでそのリクエストの性質を判断できます。
ステートレスサーバーのデメリットの1つは、必要なすべてのデータが個々のリクエストに含まれた状態で転送しなければならないことによる、ネットワークパフォーマンスの低下です。 - キャッシュ可能
- RESTアプリケーションはWebシステムであるため、クライアントと仲介サーバーがレスポンスをキャッシュする場合があります。レスポンス自体がキャッシュ可能に定義されることは必須ですが、一方キャッシュ内の無効なデータが、サーバーが処理したリクエストによって生成されたデータと大きく異なる場合、キャッシュを無効にすると、信頼性を低下させかねない、クライアントによる無効なデータの再利用を回避できます。キャッシュによって、クライアントとサーバー間のやり取りを一部削減でき、結果として平均レイテンシが抑えられ、スケーラビリティ、効率性、実感スピードが向上します。
- 統一インターフェイス
- 統一インターフェイスの使用により、アーキテクチャは簡素化かつ分離され、さまざまな部分の開発にとって有利になります。この点については後ほど説明しますが、URI、リソース、ハイパーメディアは、インタラクションの可視性を向上させシステムアーキテクチャ全体を簡素化する標準インターフェイスの作成と、パーツごとの開発に役立ちます。ただし、情報がアプリケーションに特化したフォーマットではなく標準フォーマットで転送されるため効率性は低下してしまいます。
- 階層化システム
- 階層化システムの使用により、各エレメントが隣接の階層を超えてアクセスできないようにコンポーネントの機能を制限して複雑さを低減します。システムのほかの部分に関する機能を制限することで、基板の独立性を高めます。階層にレガシーコンポーネントを封じ込めて、レガシークライアントから新しいサービスを保護できます。仲介サーバーは、ネットワーク上のロードバランシングを有効にしてスケーラビリティを向上できます。ただし、階層化システムによってデータ処理にオーバーヘッドとレイテンシが追加されることによる、実感スピードは低下してしまいます。
- コードオンデマンド(オプション)
- RESTでは、コードスクリプトのダウンロードと実行による機能の拡張がクライアントに許可されています。これによりクライアントが簡素化され、拡張性が向上します。一方で可視性は低下します。
エレメント
RESTでは、ステートレスで、スケーラブル、そしてシンプルなWebAPIを構築するためのいくつかのエレメントが「ツールボックスに搭載」されています。
- HTTP
- リソース
- URI
- ハイパーメディア
HTTP:ドキュメント転送アプリケーションプロトコル
RESTは通常、転送プロトコルとしてHTTPとともに使用されるので、いくつかのメリットがあります。HTTP動詞、ステータスコード、ヘッダーが含まれます。
動詞(Verb)
Webサービスで起こり得る状況ごとに新しい動詞を定義する代わりに、HTTPには類似の状況を同じ方法で処理する、動詞の標準セットが導入されており、これにより不必要なバリエーション除去し、より直感的なAPIを作成します。各動詞は、異なるシナリオに適した次の2つの特性を異なる組み合わせがあります。
- べき等(Idempotent)
イベントのエラー時にも操作の繰り返しが可能 - 安全(Safe)
操作はクライアント側で起こりうる事象の副次的影響を受けない
・GET
GETはサーバーからの状態の読み取りに使用されます。「安全」な操作であり、データの変更や破損の危険なく複数回実行できます。1回呼び出しても10回呼び出しても結果は同じです。「べき等」でもあるので、複数回の同一のリクエストは単一のリクエストと同じ結果になります。
・POST
POSTは、通常サーバー上の何らかの状態の作成に使用されます。「安全」でも「べき等」でもありません。従って、複数のリクエストはサーバ上にいくつかのリソースを作成します。POSTは「べき等」ではないので、金銭を扱う操作に使用すべきではありません。なぜならリクエストが何度も失敗した場合、何度も送金や支払いをさせられる羽目になりかねないからです。
・PUT
PUTはたいていサーバ上で状態の更新に使用されますが、状態の作成にも使用できます。PUTはサーバーの状態を変更するので、「べき等」ですが「安全」ではありません。PUTは「べき等」であるため、たとえば金銭に関する操作などに向いています。
・DELETE
DELETEはサーバー上の状態の削除に使用されます。サーバーから状態を削除するので、これは「べき等」ですが「安全」ではありません。以前に削除済みの状態をさらに削除してもなんの影響もないため、DELETEは「べき等」です。
レスポンスステータスコード
HTTPのステータスコードは、リクエストされたリソースの状態へのレスポンスにメタデータを提供します。これは、Webを分散システム構築用のプラットホームにするのにひと役買っています。ステータスコードは次のように分類されます。
- 1xx:メタデータ
- 2xx:すべて成功
- 3xx:リダイレクト
- 4xx:クライアント側の処理失敗
- 5xx:サーバー側の処理失敗
ヘッダー
HTTPヘッダーは、リクエストとレスポンス内の追加の情報を渡すコンポーネントです。ヘッダーは、大文字と小文字を区別しないヘッダー名、次いでコロン、そして値で構成されます。ヘッダーは次のようにグループ化できます。
- ジェネラルヘッダー:リクエストとレスポンスの双方に適用されるが、ボディで転送されるデータとは無関係
- リクエストヘッダー:フェッチされるリソースやリクエスト元のクライアントについてのさらなる情報を含む
- レスポンスヘッダー:レスポンスについての付加的な情報を含む
- エンティティヘッダー:エンティティの長さ(content-length)やMIMEタイプなど、ボディのエンティティについての情報を追加
リソース
リソースとは、「システムによって公開される、識別を持つ任意のもの」です。リソースは、アプリケーションドメインをWebクライアントに適合させる方法を提供します。リソースの例として、画像、スプレッドシート、サービス、さまざまなリソースのコレクションなどがあります。リソースはなんらかの表現(XML、JSONなど)を使ってフェッチされ、送信されます。
「値渡し(Pass-by-value)」の概念に従って、やり取りされるのはリソース自体ではなく、リソースの表現です。前述のRESTの定義に従うと、リソースは作業を進めていくためにネットワーク上で転送されるドキュメントのことになります。ドメインの状態を表すリソース状態はサーバ側が担当し、クライアントはただリソースをフェッチしたり送信したりしてアプリケーションの状態を進行させます。一方、アプリケーション状態は特定のアプリケーションの目的に対する進捗を表すため、クライアント側が担当します。
リソースは特定のシステムのドメイン内でコンセプトを表現するので、名詞で命名され、そしてURIを使って識別されます。
URI(Uniform Resource Identifier:統一資源識別子)
URIは、あるリソースを別のリソースと区別します。リソースにアクセスし、操作するために、リソースには少なくとも1つのアドレスが必要です。これはprotocol+host+pathで構成されます。
特定のリソースのURIはサーバーの裁量で変更される場合があるので、クライアントはそうしたURIに接続されるべきではありません。ここでハイパーメディアが最大のメリットを発揮します。なぜならハイパーメディアには、特定のURIからクライアントを離脱させ、アプリケーションプロトコルにセマンティクスを追加する方法があるからです。
ハイパーメディア
ハイパーメディアは、レスポンス内でハイパーメディアコントロール(リンクとフォーム)を使って、次に表示できることと、それを表示するための特定のURIについてクライアントに伝えます。特定のアプリケーション用の具体的なハイパーメディアフォーマットは、アプリケーションのメディアタイプで定義されます。
ハイパーメディアリンクは、リンクされるリソースにアクセスするURIを指定するhref属性と、関係の意味を定義するrel属性によって構成され、こうしてアプリケーションの状態遷移にセマンティクスが加えられます。リンクを使うことで、サーバーはレスポンスに新しいリンクを埋め込んで、既存のクライアントを切断することなく新たな機能を提供できます。
サーバーがレスポンス内に、以前に定義されたリンクを保持するかぎり、クライアントはそのリンクを追って、新しい状態に変わる前の状態に戻れます。クライアントは、新しい状態にアクセスしなければならない場合のみ、更新される必要があります。ハイパーメディアの別のメリットは、ディスカバラブルなセルフドキュメント型のプロトコルを生成する手段が与えられるので、ディスカバラビリティ(見つけられやすさ)を高めるられることです。
クライアントは固定URLでアプリとのやり取りを開始し、クライアントがリンクを追うことによって、アクションが生じます。これらのアクションでは、リンクはメディアタイプを使ってフォーマットされ、サーバーによって各レスポンス内で提供されます。
メディアタイプとリンクは、アプリケーションサーバーとクライアントの間のコントラクトを定義します。クライアントは、リンクを使いアプリケーションの状態を操作することによってシステムとやり取りします。これがHATEOAS(Hypermedia as the engine of application state:アプリケーションのエンジンとしてのハイパーメディア)の真意です。
ハイパーメディア(すでに定義済みのエレメントに加えて)は、RESTfulの真意です。
リチャードソン成熟モデル(Richardson Maturity Model)
リチャードソン成熟モデルは、RESTの意味するところと、Webアプリケーションの特性の説明の仕方を理解するのにとても役立ちました。リチャードソン成熟モデルはRESTシステムの構成要素を3段階に分け、RESTful思考におけるアイデア、コンセプト、メリットを理解する方法を与えてくれます。これは評価機構というより、むしろ教育モデルといえます。
リチャードソン成熟モデルについての詳しい説明は、Martin Fowlerのブログを参照してください。
※この記事のオリジナルはcodurance.comで公開されたものです。
(原文:What Does RESTful Really Mean?)
[翻訳:新岡祐佳子]
[編集:Livit]