ヘテロジニアスなアプリケーション間の通信を実装するための「適切な」手法について議論が行われているということを、あなたは知っているかもしれないし、知らないかもしれません。そういった状況下で、現在の主流は明らかにSOAP、WSDL、WS-*仕様という世界をベースとしたWebサービスにフォーカスしています。しかし、少数派の人たちの中で、より良い方法があると主張する人がいます。それが、REST(REpresentational State Transferの略)です。本稿では、本筋から外れることなく、RESTとRESTfulなHTTPアプリケーション統合への実用的な説明を試みようと思います。これらの考え方の説明については、より詳細に踏み込んで説明をするつもりです。私の経験上、誰かが始めてこのアプローチを経験することで一番議論が活発になると考えています。
RESTの主要な原則
大抵の場合、RESTの説明は、形式的な定義と背景から始まります。私の場合、それを少し後回しとし、シンプルで実用的な定義を提供しようと思います。 RESTは、HTTPやURIといったWeb標準がどのように利用されるべきなのか(大抵、多くの人たちが実際に行うこととはかなり異なるのですが)を定めた原則のセットです。アプリケーションを設計している際にRESTの原則を守れば、有益なWebのアーキテクチャを活用したシステムとなるでしょう。要約すると、5つの主要な原則は次のとおりとなります。- 全ての「もの」にIDを与える
- 「もの」をリンクづける
- 標準的な構文を使用する
- 複数の表現によるリソース
- ステートレスに通信する
全ての「もの」にIDをつける
私は、公式に正しい用語である「リソース」の代わりに「もの」という用語を使用しています。何故なら、これが専門用語の中に隠されてしまうべきではない非常にシンプルな原則であるからです。人が作ったシステムについて考えるとき、大抵の場合は既知のメリットである重要な抽象概念のセットが存在しています。 Webに関しては、特定すべきすべてのものは、明確にIDを付与します。IDに対する統一した概念がそこにあるのです。それが、URIです。URIは、全体的な名前空間を構成し、主要なリソースをユニークなグローバルIDに特定するためにURIを利用します。
ものに対する一貫性のあるネーミングスキームの主な利点として、独自のスキームを考えなくて良いということが挙げられます。それはつまり、既に定義されているものに頼ることができ、世界規模で十分に機能していて、実質全ての人に知られているものです。あなたが最後に構築したアプリケーション(それが RESTfulで無いものと仮定して)の中で任意の高度に抽象化されたオブジェクトを考えるなら、ここから利益を得るであろうケースが多く存在する可能性が高いです。あなたのアプリケーションに顧客の抽象概念が考慮されているなら、私はユーザーが同僚に対し、Eメールを通して特定の顧客の関連情報を送信することが可能であるだろうということや、彼らのブラウザにそれのブックマークを作るとか、紙切れにそれを書き込むということを無理なく確認することができます。この点について強調しておきたいことは、次のことです。Amazon.comのようなオンラインストアが製品全てをユニークなID(即ち、URI) で特定しないならば、それがとても恐ろしいビジネス決定であるということを想像してみてください。
この考えに取り組むとき、多くの人々は、直接データベースエントリ(またはID)を公開しなければならないのではないかと疑問に思います。そして、オブジェクト指向が実用される時代に、永続化の部分の実装の詳細を隠蔽するということを私たちが理解したので、そういったちょっとした考えにはしばしば愕然とさせられます。しかし、これは全く対立するものではないのです。通常、URIで特定できるメリットを持つ「もの」(即ち、リソース)は、データーベースエントリよりもはるかに抽象的なのです。例えば、発注のリソースは品目の発注、住所、さらには個々に識別可能なリソースとして公開したくないであろうその他多くのリソースで構成されているでしょう。さらに特定される価値のあるもの全てを特定するという考えに則ると、典型的なアプリケーション設計では通常見られないリソースを作成することになります。例えば、プロセス、プロセスのステップ、販売、交渉、見積もり請求などといったもの全てが、特定する価値のある「もの」の例となります。こうして、次々とRESTfulでない設計から永続化エンティティをより多く作成する方向に移ることができるのです。
あなたが思いつくであろうURIの例を、いくつか挙げてみます。
http://example.com/customers/1234
http://example.com/orders/2007/10/776654
http://example.com/products/4554
http://example.com/processes/salary-increase-234
私が人が読むことの出来るURIを作成することを選ぶとして(RESTfulな設計という意味でそれが前提条件という訳ではないのですが、有用な考えです)、それらの意味を推測することが非常に容易でなければなりません。それらは、きちんと個々を特定します。しかし、以下を見てください。
http://example.com/orders/2007/11
http://example.com/products?color=green
一見、これらは異なるものであるように見えます。結局のところ、それらはものを特定しているのではなく、ものの集合を特定しているのです(1つめのURIは 2007年11月に注文を確定したすべての商品を特定しており、2つめは緑色の商品の集合を特定しています)。しかし、これらの集合も実はそれ自体が「もの」(リソース)であり、特定するメリットは間違いなくあります。
ここで留意すべき点は、単一のグローバルに統一されたネーミングスキームを持つメリットが、ブラウザでのWebの使用法とマシン間での通信の両方に適用されるということです。
最初の原則をまとめます。特定する価値のある全てのものを特定するためにURIを利用してください。具体的には、個々のもの、ものの集合、仮想的/物理的なもの、計算結果を表しているかどうかに関わらず、アプリケーションが提供する"高度に抽象化された"リソース全てが対象となります。
「もの」をリンクづける
次にみる原則は、少し危険な形式的記述を持っています。それは、「アプリケーションの状態からなるエンジンとしてのハイパーメディア(※1)」 (HATEOASと略されることがあります)です。(実際、私はこれを作っていないのですが。)その中心となるところは、ハイパーメディアの考え方にあります。言い換えると、リンクの考えです。リンクは、HTMLという形で皆が知っているものですが、人が利用する上での制限は全くありません。以下のXML を見てください。
(※1)アプリケーションをハイパーメディアというエンジン(駆動するための動力源)を利用することによって、(次に取りうる)状態に遷移していくということ
<order self='http://example.com/customers/1234' >
<amount>23</amount>
<product ref='http://example.com/products/4554' />
<customer ref='http://example.com/customers/1234' />
</order>
このドキュメントの製品と顧客のリンクを見ると、それらを検索するアプリケーションが、より多くの情報を得るために、どのようにしてリンクをたどることができるかということについて、容易に想像することができるでしょう。もちろん、あるアプリケーション特有のネーミングスキームを順守している単純な"id" 属性があることは問題ではあります(但し、それはアプリケーションコンテキスト内に限られます)。URIを利用したリンクアプローチの美しさは、リンクが異なるアプリケーション、異なるサーバー、あるいはよその国の異なる会社であったとしても、そこから提供されるリソースを指し示すことができるということです。つまり、ネーミングスキームがグローバルスタンダードなので、Webを構成する全てのリソースは、お互いにリンクしあうことができるのです。
ハイパーメディアの原則には、さらに重要な側面があります。アプリケーションの「状態」の部分です。手短に言えば、サーバー(もしくは、もし望むのであればサービスプロバイダ)がクライアント(サービスコンシューマ)のリンクのセットを提供することで、クライアントがリンクに従ってある状態から次の状態へとアプリケーションを遷移できるようにします。私たちは、すぐに他の記事でこの側面の効果をみることができるでしょう。当面は、リンクはアプリケーションを動的に作るための非常に便利な方法であるということを心に留めておいて下さい。
この原則のまとめです。可能であれば何でも、特定可能なもの(リソース)を参照するためにリンクを使用します。ハイパーリンクは、WebをWebたらしめるものです。
標準的な構文を使用する
最初の2つの原則に関する議論には、暗黙の仮定がありました。それは、利用するアプリケーションが、URIで実際に意味のある何かを行うことができるということです。もしバスの端に書かれたURIを見たなら、ブラウザのアドレスフィールドにそれを入力してリターンキーを押下することができます。しかし、ブラウザはそのURIで何をすべきかについて、どのようにして知るのでしょうか?
結論から言うと、リソース全てが同じインターフェースと同じメソッドのセットをサポートしている(可能であれば操作も)ので、それをどうするべきかについて分かっています。HTTPが、次の動詞を呼びます。誰もが知っている2つのメソッド(GETとPOST)に加え、PUT、DELETE、HEAD、 OPTIONSを含む標準的なメソッドのセットです。これらのメソッドの意味するところに関しては、HTTPの仕様で定義されており、それらの振る舞いに関しても一部保証されています。もしあなたがオブジェクト指向開発者であるなら、RESTful HTTPシナリオの全てのリソースが、次のような形でクラスを継承しているとイメージしてください (一部、Java/C#風の偽のシンタックスで、主要なメソッドのみ記述しています) 。
class Resource {
Resource(URI u);
Response get();
Response post(Request r);
Response put(Request r);
Response delete();
}
同じインターフェースが全てのリソースに対して使用されるので、表現の取得を気にする必要がありません。つまり、それの表現であるGETを使用すればよいのです。GETのセマンティクスについては仕様で定義されているので、それを呼ぶ際に何の責任もないということが確信できます。これが、GETが「安全(※2)」と言われている所以です。GETは非常に効果的で洗練されたキャッシュ機能をサポートしているので、多くの場合、サーバーにリクエストを送信する必要すらありません。GETは、冪等性(べきとうせい)も保証しています。例えば、GETリクエストを発行して結果が得られなかった場合、リクエストが目的の場所まで到達しなかったのか、それともレスポンスが返ってくる途中で消失したのかは分からないでしょう。冪等性の保証が意味するところは、リクエストの再呼び出しが簡単にできるということです。冪等性は、PUT(基本的な意味は、データと共にリソースを更新すること、あるいはデータが存在していなかった場合にURIを作成することです)やDELETE(問題なく削除が行われるまで、何度も試行することができることです)に対しても保証されます。通常、新しいリソースを作成するということを意味するPOSTは、任意の呼び出し処理に使用することもできるので、安全でないうえに冪等でもありません。
(※2)リソースに対して、副作用を与えないという意味での「安全」。
あなたがRESTfulな手法でアプリケーションの機能(可能であれば、サービスの機能)を公開するならば、この原則と制限は同じようにあなたに適用されます。あなたが異なる設計アプローチをしているのなら、それを受け入れるのは難しいでしょう。結局、少しの操作で表現できること以上に、あなたのアプリケーションが非常に多くのロジックを持っているということを納得させられるでしょう。ただし、そうではないということを納得しようとするには、いくらかの時間が必要になるでしょう。
以下にあげる簡単な調達シナリオの例を見てください。
2 つの定義されたサービスがあります(特別な実装技術は何もありません)。これらのサービスに対するインターフェースは、固有なものです。それは、私たちが話しているOrderManagementとCustomerManagementです。クライアントがこれらのサービスを利用したければ、特定のインターフェースに対してコード化される必要があります。つまり、これらのインターフェースが意味を持って相互に作用するよりも前に、作られたクライアントを使用する方法がないのです。そのインターフェースはサービスのアプリケーションプロトコルを定義します。
RESTful HTTPアプローチでは、HTTPアプリケーションプロトコルを構成する一般的なインターフェースでなければなりません。例えば、以下のようなものを考えるかもしれません。:
特定のサービスのオペレーションが、標準的なHTTPメソッドにマップされているのが分かるでしょう。曖昧さをなくすことで、新しいリソースの世界全体ができあがりました。「それは不正行為だ!」と言う声が聞こえてきます。いや、そうではありません。顧客を特定するURIのGETは、 getCustomerDetailsオペレーションと同じ意味を持っています。これらのことを視覚化するために、以下の三角形の図を利用します。:
3 つの頂点を、回せるノブと考えてください。初めのアプローチで見たように、多くのオペレーションと多くの種類のデータと一定の「インスタンス」がありました(基本的には、サービスと同じくらいの数)。次に、決められたメソッドを呼び出すための、一定のオペレーションと多くの種類のデータや多くのオブジェクトがありました。ここでのポイントは、両方のアプローチで目的のことが概ね説明できるということを示すことにあります。
なぜ、これが重要なのでしょうか? それはあなたのアプリケーションがWebの一部となるからです。つまり、Webをインタネットで最も成功したアプリケーションに変えたことへの貢献は、追加するリソースの数に比例しています。RESTfulアプローチであれば、あるアプリケーションが数百万の顧客のURIをWebに追加するかもしれないのです。CORBAの時代に設計されたアプリケーションで同じ手法を設計しようとしたら、通常は、単一の「エンドポイント」となります。つまり、鍵を持っている人に対してのみリソースの世界への入場を与える非常に小さなドアになってしまいます。
均一なインターフェースも、HTTPアプリケーションプロトコルを解釈するあらゆる構成要素がアプリケーションと相互作用することを可能にします。ここから利益を得るコンポーネントの例は、curl、wget、proxies、caches、HTTPサーバー、ゲートウェイだけでなく、Google、 Yahoo!、MSNやさらに多くのものなど、一般的なクライアントにまで及びます。
まとめです。リソースと相互作用することができるクライアントのために、デフォルトアプリケーションプロトコル(HTTP)を正しく実装する必要があります。言い換えれば、GET、PUT、POST、DELETEといった標準メソッドを利用するということです。
複数の表現によるリソース
これまで、私たちは少しだけ面倒なことを無視していました。それは、クライアントが取得したデータ、即ち、GETやPOSTリクエストによって得られた結果を扱う方法をどのようにして知るのか? ということです。 HTTPによるそのアプローチは、データのハンドリングとオペレーションの呼び出しの間で関心の分離を可能にします。言い換えれば、特定のデータフォーマットを操作する方法を知っているクライアントが、そのフォーマット内での表現を提供することができる全てのリソースとやりとりをすることができるということです。これについて、再度、例で説明することにしましょう。HTTPのコンテントネゴシエーションを利用して、クライアントは特定のフォーマットでの表現を問い合わせることができます。
GET /customers/1234 HTTP/1.1
Host: example.com
Accept: application/vnd.mycompany.customer+xml
その結果は、顧客情報を表現するある会社固有のXMLフォーマットであるかもしれません。もし、クライアントが異なるリクエストを送信するなら、例えば以下のようになります。:
GET /customers/1234 HTTP/1.1
Host: example.com
Accept: text/x-vcard
その結果は、VCardフォーマットの顧客アドレスとなりました。(私は、HTTPのContent- typeヘッダーのデータタイプに関するメタデータを含むレスポンスを示しませんでした。) これは、理想的な形となっています。つまり、リソースの表現が標準フォーマットであるべきだということです。クライアントが、HTTPアプリケーションプロトコルとデータフォーマットのセットの両方を「知っている」ならば、意味のある方法によって、世界のRESTful なHTTPアプリケーションすべてと相互作用可能となります。残念ながら、全てに対する標準フォーマットはありません。しかし、あなたはおそらく標準フォーマットを信頼することのできる会社内、もしくは共同パートナーたちの間でのより小さなエコシステムを、どのようにして構築するのかということを考えることができるでしょう。もちろん、この全てがサーバーからクライアントに送信されたデータに適用されるだけでなく、逆の方向に対しても適用されます。つまり、特定フォーマットのデータを利用するサーバーは、アプリケーションプロトコルに従っているものを提供したクライアントの特定のタイプについて知る必要がないのです。
実際には、リソースが複数の表現を持つことについて、もう1つ重要なメリットがあります。もしリソースをHTMLとXMLによる両方の表現で提供するならば、自身のアプリケーションによって利用可能なだけでなく標準的なWebブラウザ全てによって利用可能となります。言い換えれば、アプリケーションの情報がWebの利用方法を知っている人たち全てに対して利用可能なものとなるということです。
これを有効に利用する別の方法があります。それは、アプリケーションのWeb UIをそのままWebAPIに変えることができるということです。結局、APIの設計は、しばしばUIを通してできることすべてがAPIによってもできなければならないという考えによって進められます。2つのタスクを1つにまとめることは、人間と他のアプリケーションに対するより良いWebインターフェースを得るための非常に有益な手法と言えます。
まとめです。異なるニーズに対して、リソースにおける複数の表現を提供してください。
ステートレスに通信する
私が説明する最後の原則は、「ステートレスに通信する」です。まず第一に、RESTがステートレスの考えに基づいているということを強調するのは重要なことですが、これが公開されたアプリケーションが機能的に状態を持つことができないということではありません。ただ、実際には、それは多くのシナリオにおいてアプローチ全体が非常に役に立たないものとなると思われます。RESTでは、リソースの状態に変化するか、若しくはクライアント上に保持されるかといった状態を指示します。言い換えれば、サーバーが、ある単一のリクエストを超えてクライアント全てに対するある種の通信状態を保持する必要がないということです。それの最も明確な理由は、スケーラビリティにあります。つまり、もしクライアントの状態を保持する必要があるならば、多くのクライアントが相互にやり取りすることで、サーバーの台数がたくさん必要になるでしょう。(注意点として、通常、こういった場合は何らかの再設計が必要になります。結果として、あるセッションの状態をURIに対応させることが簡単にできなくなり、それはRESTfulとは呼べません。)
しかし、もっと重要であると思われる別の側面があります。それは、ステートレスという制約により、2つの連続したリクエストにおいて同じサーバーと通信する必要がないので、サーバーの変更に対してクライアントが独立しています。一方、クライアントは、サーバーからリンクを含んだドキュメントを受信することができるので、いくつかの処理を行っている間、サーバーをシャットダウンしたり、ハードディスクを取り出して交換したり、ソフトウェアの更新や再起動が可能です。クライアントがサーバーから受け取ったリンクの中のいずれかに従うなら、特に問題となることはないでしょう。
理論的な視点でのREST
実は、打ち明けなければならないことがあります。今まで私が説明していたのは、本当のRESTではありません。少し、物事を単純化しすぎたかもしれません。しかし、私はいつもとは少し違ったものから始めたかったので、初めに形式的な背景とRESTの歴史について説明しませんでした。いくぶん簡単ではありますが、それについて説明させてください。
まず初めに、私はHTTPそれ自身と、RESTfulな方法でのHTTPの使用からRESTを切り離すために、この辺の話を避けてきました。これらの異なる側面の間の関係を理解するために、私たちはRESTの歴史を見なければなりません。
RESTという言葉は、Roy T. Fielding博士(サイト・英語)のPhD 論文(英語)によって定義されました(実際にそのリンクをたどりたいと思うでしょう。論文であるので非常に読みやすいのは明らかです)。Roy博士は、HTTPとURI を含む必要不可欠なWebプロトコルの主要な設計者の一人であり、そのあとで多くの考えを論文として形式化しました。(当然ですが、その論文は「REST のバイブル」と考えられており、最終的には著者がその言葉を考えたので、当然ながら彼がRESTについて書いた全てが、権威あるものとして考える必要があります。) その論文の中で、Roy博士はアーキテクチャスタイルについて説明するためのメソドロジーを初めに定義しています。それは、アーキテクチャアプローチを背景とした考えを中心として説明された高度に抽象化されたパターンです。それぞれのアーキテクチャスタイルは、それを定義する制約のセットとなっています。「null style」(それには全く制約がありません)を含むアーキテクチャスタイルの例として、パイプ、フィルター、クライアント/サーバー、分散オブジェクト、そしてRESTがあります。
これら全てが、非常に抽象的に思えるのなら、あなたは正しいです。REST自身は、多くの異なる技術を利用して実装されうる高水準なスタイルなのです。そして、その抽象的な特性のために異なる値を使うことを具体例をあげて示しました。たとえば、RESTは、リソースや統一インターフェースの考えを持っています。つまり、全てのリソースが同じメソッドによって応答するという考えなのです。しかし、RESTはどのメソッドでなければならないのかや、メソッドの数がどれくらい必要であるのかといったことには言及していません。
REST スタイルを「具現化」したものの1つが、HTTP(と、URIなどの関連する標準セット)です。もしくは、少し抽象的になりますが、Webのアーキテクチャそれ自身であるとも言えます。先に挙げた例で続けると、HTTPは、RESTの統一インターフェースをHTTPの動詞(操作)からなる特別な形で「具体化」したものと言えます。Fielding博士がWebの後でRESTスタイルを定義したように、(少なくともそのほとんどが)すでに「できあがっている」ものなのです。100%適合しているかどうかについて議論する人もいるかもしれません。しかし、いずれの場合においても、Web、HTTP、URI は、非常にメジャーであり、全体としてRESTスタイルで関連するものだけで作られています。そして、Roy Fielding博士は、RESTの論文の著者であり、Webアーキテクチャデザインに強い影響を与えた人でもあります。したがって、これらの結果は、当然のことと言えます。
最後に、私は、随所で「RESTful HTTP」という言葉を使いました。それは、次のシンプルな理由によります。HTTPを使う多くのアプリケーションは、RESTの原則に従っていません。少し正当化するものとして、RESTの原則に従っていないHTTPを使用することは、HTTPの誤用に等しいと言えます。もちろん、これは少し肩入れしすぎなように聞こえるかもしれません。いくつかのトレードオフを含んだすべての制約が、特定の状況下で受け入れられないかもしれないので、実際には、 RESTの制約に違反することがしばしば起こりえるのです。しかし、多くの場合は、単純にそのメリットを理解していないという理由でRESTの制限が侵されます。あまり良くない例を示します。RESTの「安全な」制約を侵して、オブジェクトの削除としての呼び出しにHTTP のGETを使用するということです。しかし、これは違和感の無いことかもしれません(サーバー開発者が何を意図しているかということを、クライアントが意識する必要がないのですから)。以上となりますが、これよりも詳しいことやより顕著な違反については、今後の記事の中でフォローしていきます。
要約
本稿では、WebのアーキテクチャであるRESTに潜む概念について、実用的な説明を行いました。機能を公開するRESTful HTTPアプローチは、RPC、分散オブジェクト、Webサービスとは異なります。この違いを真に理解するためには、いくらかのマインドシフトが必要になります。しかしながら、RESTの原則について知っておくことは、Web UIだけを公開するアプリケーションを構築したり、アプリケーションのAPIをWebの世界の一員としたいときには、有益なものとなるでしょう。
Stefan Tilkov (source)は、InfoQのSOAコミュニティをリードする編集者で、共同創設者の一人です。彼は、コンサルタントやドイツやスイスをベースとしたinnoQ(サイト・英語)をリードするRESTafarian(※3)です。
(※3)RESTafarian REST主義者
===おまけ===
RESTの情報
- yohei-y:weblogのREST入門
http://yohei-y.blogspot.com/2005/04/rest_23.html
原文はこちらです:http://www.infoq.com/articles/rest-introduction