Roy Fieldingは、最近、次のように述べています。(サイト)
REST APIは、固定したリソース名や階層(クライアントとサーバーの明らかな組み合わせ)を定義してはいけません。サーバーは、自身の名前空間を制御する自由がなければならないのです。
上述したようなことは、取り組むのが困難です。固定されたリソース階層なしで自身の名前空間を制御するなら、クライアントやそれがより重要であるクライアントの開発者は、どのようにしてリソースのURIを取得したり見つけたりするのでしょうか?結局、長い間、分散のクライアントサーバー開発における基本的な前提の一つとして、そういったアプリケーションをビルド、保守、管理するために、私たちは演繹的にアプリケーションのインターフェースに関する形式的な記述を必要としています。Roy Fieldingのメッセージはこの前提に反論するものと思います。
RESTfulなシステムの記述に関する議論は、新しいことではありません。大抵の場合、当該の議論は上述したような考えで完結しています。たとえば、討論: RESTに記述言語は必要か?(参考記事)の記事を参照してください。昨年、infoQではその議論のいくつかをまとめています。そのときの状況と現在とで、あまり違いはありません。
RESTfulアプリケーションのための形式的記述言語について、さまざまな賛否両論が述べられているのをよそに、WADL(サイト)のような記述言語は、一定の地位を得ています。しかし、それは機械が解釈できる「標準」言語ではないため、サーバーアプリケーションがとる最も一般的な手法は、すべてのURI、HTTPメソッドのサポート、表現構造(たとえば、XMLやJSON)をドキュメント化することです。それは、クライアントアプリケーション開発者がコードを書くためにそういったドキュメンテーションに頼ることができるようにするためのものです。
しかしながら、上述のRoy Fieldingの言葉を言い換えると、このようなアプローチはRESTの基本的な原則の一部と相反します。たとえ私たちがこの異議を無視するとしても、 HTTP上に分散型アプリケーションをRESTfullに構築しようとしている人たちには、根本的な問題が残ります。契約を形式的に定義することなくサーバーからの取得はどうするのでしょうか?契約なしでクライアントとサーバーが正しく実装しているということをどのように確かめるのか、それぞれの設計仕様書だけでなく、その他、適切なビジネス/技術ポリシーはどうするのでしょうか?
アプリケーションプロトコルとしてHTTPを使用し、RESTfullな構築をしている分散型アプリケーションには、同じような性質と種類の契約があります。私たちは、何を探し、どこを探すかを知る必要があります。同じ方向にしたがい、私たちが記述言語に向かうならば、それはWSDLやWADLと同様なものとはならないでしょう。本稿での私のゴールは、以下の問題に答えることです。
- 何故RESTfulアプリケーションに対する標準的な記述言語が未だに無いのか?
- RESTfulアプリケーションに対する契約はどのようにすればよいのか?
- そのような契約を理解し、優位性を得ることができるようにするための構築に必要なソフトウェアはどのようなものか?
- 私たちが機械が解釈可能な記述へと向かうならば、それをどのようにすればよいか?
例から始めさせてください。
例
タスクは、ある銀行口座から同一顧客の他の口座へと残高の一部を転送することができるクライアントアプリケーションを記述することです。
最初にクライアントとサーバー間のすべてのインタラクションを説明します。次に、契約に関する可能な記述を見ます。
Step 0:ユーザはクライアントにログインします。今回の議論に集中するために、セキュリティの観点はすべて省かせて頂きます。
Step 1:クライアントは、顧客IDを使用している2つの口座を検索するために、URI http://bank.org/accounts?findby=7t676323a
を使います。ここで、7t676323a
はいくつかの口座を銀行に登録している顧客のIDです。レスポンスでは、サーバーが2つの口座、つまり、AZA12093
とADK31242
、それぞれの顧客IDと現在の残高を返します。
200 OK Content-Type: application/xml;charset=UTF-8 <accounts xmlns="urn:org:bank:accounts"> <account> <id>AZA12093</id> <customer-id>7t676323a</customer-id> <balance currency="USD">993.95</balance> </account> <account> <id>ADK31242</id> <customer-id>7t676323a</customer-id> <balance currency="USD">534.62</balance> </account> </accounts>
http://bank.org/account/AZA12093 http://bank.org/account/ADK31242
この例では、クライアントが情報を持つことで口座振替に加入する必要がありますが、これらのリクエストは省略させて頂きます。
Step 3:クライアントは、以下の通りにPOSTリクエストを送信することで、口座振替をおこないます。
POST /transfers Host: bank.org Content-Type: application/xml;charset=UTF-8 <transfer xmlns="urn:org:bank:accounts"> <from>account:AZA12093</from> <to>account:ADK31242</to> <amount currency="USD">100</amount> <note>RESTing</note> </transfer>
サーバーは口座に対する支店番号を取得し、振替を行うためにいくつかの銀行システムに振替を送信します。以下を返します。
201 Created Content-Type: application/xml;charset=UTF-8 <transfer xmlns="urn:org:bank:accounts"> <from>account:AZA12093</from> <to>account:ADK31242</to> <id>transfer:XTA8763</id> <amount currency="USD">100</amount> <note>RESTing</note> </transfer>
振替はまだおこなわれていません。振替は複数営業日にわたって、非同期におこなわれるでしょう(銀行間の取引としては珍しくありません)。そして、クライアントはその状態を探すために取引のIDを使用することができます。
Step 4:1日後、クライアントは状態を検索するために、GETリクエストを送信します。
GET /check/XTA8763 Host: bank.org 200 OK Content-Type: application/xml;charset=UTF-8 <status xmlns="urn:org:bank:accounts"> <code>01</code> <message xml:lang="en">Pending</message> </status>
ここで留意すべき点は、この実行がリソース、URI、表現、HTTPの統一インターフェースを使用していますが、RESTfulではないということです。次のセクションで見ることになるでしょうが、この例ではRESTの重要な制約の一つにおける優位性を享受していません。それは、ハイパーメディアがアプリケーションの状態のエンジンとなることです。
このRESTfulを作ろうとする前に、この例を利用するために考えられるユーザードキュメントを書いてみます。
Bank.Org のAPI - URI
http://bank.org/accounts?findby=someparams
預金口座を検索するために、このURIでGETリクエストを送信します。これは、
accounts
ドキュメントを返します。詳細はXMLスキーマを参照してください。
http://bank.org/account/{account-id}
口座の詳細を得るために、このURIでGETリクエストを送信します。この
{account-id}
は、口座のIDです。これは、account
ドキュメントを返します。詳細はXMLスキーマを参照してください。
http://bank.org/transfers
口座振替を作成するために、このURIでPOSTリクエストを送信します。リクエストのボディには、
transfer
ドキュメントが含まれています。リクエストが成功すると、サーバーはtransfer
ドキュメントを返します。詳細はXMLスキーマを参照してください。
http://bank.org/check/{transaction-id}
振替の状態を検索するために、このURIでGETリクエストを送信します。この
transaction-id
は、口座振替のIDです。これは、status
XMLドキュメントを返します。詳細はXMLスキーマを参照してください。
この種のドキュメントは、現在、最も一般的なものです。それは、クライアントがいつも使うすべてのURIを含みます。また、それぞれのURIで使用することのできるHTTPメソッドを記述します。それには、表現の記述も含まれます。つまり、この例ではXMLドキュメントです。
しかし、この種のドキュメントには2つの問題があります。まず第1に、それは形式的に機械が解釈可能な記述を求めている人への手助けとなりません。機械が解釈可能な記述ではないので、テストや契約を実行するための一般的なソフトウェアツールを構築することができません。そのような一般的なソフトウェアツールの欠如は、ソフトウェアの管理や統治のためのツールを配備する必要のある人たちにとっての大きな障害となります。あなたは、機械が解釈可能なものと同等のものを提供するために、WADL(サイト)やWSDL 2.0(サイト)の使用を考えるかもしれません。
第2に、より重要なことですが、この方法でサーバーのインターフェースを記述すると、WADLやWSDL 2.0のような機械が解釈可能であれ、人間が理解可能であれ、RESTが求めている制約の2つに違反します。それは、(a)メッセージが自身記述的であること、(b)ハイパーメディアがアプリケーション状態のエンジンとなること、です。それはどのくらい重要で、何故重要なのでしょうか?
制約へ
RESTの重要な制約は、(a) リソースの識別、(b) 表現によるリソースの操作、(c) 自己記述的メッセージ、(d) アプリケーション状態のエンジンとしてのハイパーメディア、です。
HTTPを用いたRESTfulアプリケーションのメッセージは、次の2つの効力により自己記述的なものとなります。第1に、ステートレスな統一インターフェイスを利用すること、第2に、コンテントネゴシエーション、キャッシュや楽観的な同時並行性のための条件付きリクエストといったHTTPのさまざまなプロトコルの側面を実装することに加え、メッセージのコンテンツを記述するためのHTTPヘッダーを利用することです。
HTTPメソッドの利用とリクエスト/レスポンスのヘッダーを見ることで、プロキシやキャッシュなどの仲介エンティティは、プロトコル(すなわち HTTP)のどの部分がどのように使われているのかを判読することができます。そのような自己記述的メッセージにより、クライアントサーバーのインタラクションを可視的(たとえば、キャッシュに対して)で、信頼性(たとえば、ある部分の障害の検知やリカバリ)があり、スケーラブルなものとします。
第4の制約、すなわち、アプリケーション状態のエンジンとしてのハイパーメディアには、2つの目的があります。第1に、それによりステートフルな状態からプロトコル(すなわちHTTP)を解放します。第2に、それによりサーバーの進化を可能とし(たとえば、新しいURIを導入する)、クライアントとサーバーを疎結合に保ちます。
前のセクションで見たように、サーバーが表現の記述を提供する場合、それはHTTPが持つ自己記述的の優位性を享受していません。HTTPでは、クライアントとサーバーは「メディアタイプ」を使用したり、リクエスト内に見られるContent-Type
ヘッダーやメッセージのコンテンツを記述するためのレスポンスを利用し、XMLスキーマではありません。メディアタイプは、オブジェクトのクラスやXML要素のスキーマタイプのようなものです。
さらに、サーバーがクライアントに対するURIすべてを記述しているとき、それは単独で進化することができません。さらに、そのインターフェースは脆くなります。すべてのURIの変更に対して、そのほとんどが、既存のクライアントを変更することになるでしょう。しかし、接続の必要があるURIを知ることなく、クライアントを記述するにはどうしたらよいのでしょうか?
その答えは、既に知られている関係であるリンクの使用にあります。リンクは、クライアントが実行時にURIを見つけるために使用することができる間接的なものです。リンクには少なくとも2つのプロパティがあります。それは、URIと関係です。関係がリンクの型や種類を記述するのに対して、URIはリソース、あるいはリソースの表現を示しています。本来のRESTfulなサーバーアプリケーションは、その表現の中に事前定義された関係と共にリンクを含めることにより、URIをクライアントに伝えます。したがって、すべてのURIを演繹的に覚えるのではなく、クライアントが実行時にリンクからURIを取得すればよいのです。その結果、サーバーは同じサーバーや互換性のある動作を提供している別のサーバーに対して、URIの変更や新規のURI追加でさえも自由に行うことができるのです。
最後に、クライアントが次におこなうことができること指示することで、サーバーが表現の中で返すリンクはコンテキスト依存になります。言い換えれば、リンクは、実行時にワークフローの形式の中でクライアントとサーバー間の契約を動的に記述します。
まとめると、RESTfulアプリケーションでは、契約には3つの異なる要素を含みます。それは、統一インターフェース、表現のメディアタイプ、リソースへのコンテキスト依存のリンクです。
作り話のように聞こえますか?実際にその契約を示すために、上記の例を書き直してみます。
例 - 書き直し
Step 0:前の通り。
Step 1:クライアントは口座を検索するために、同じURI http://bank.org/accounts?findby=someparams
を使用します。今回は、サーバーは別の種類のレスポンスを返します。
200 OK Content-Type: application/vnd.bank.org.account+xml;charset=UTF-8 <accounts xmlns="urn:org:bank:accounts"> <account> <id>AZA12093</id> <link href="http://bank.org/account/AZA12093" rel="self"/> <link rel="http://bank.org/rel/transfer edit" type="application/vnd.bank.org.transfer+xml" href="http://bank.org/transfers"/> <link rel="http://bank.org/rel/customer" type="application/vnd.bank.org.customer+xml" href="http://bank.org/customer/7t676323a"/> <balance currency="USD">993.95</balance> </account> <account> <id>ADK31242</id> <link href="http://bank.org/account/ADK31242" rel="self"/> <link rel="http://bank.org/rel/transfer" type="application/vnd.bank.org.customer+xml" href="http://bank.org/transfers"/> <link rel="http://bank.org/rel/customer" type="application/vnd.bank.org.customer+xml" href="http://bank.org/customer/7t676323a"/> <balance currency="USD">534.62</balance> </account> </accounts>
このレスポンスでは、Content-Type
ヘッダの値とURIを含んでいるリンクに注意してください。
Step 2:クライアントが各々の口座についてより知りたければ、それは上記のレスポンスの「self
」のリンクからURIを抽出することができます。そして、そのURIに対しGETを送信します。
Step 3:口座振替を開始するために、クライアントは上述の口座の一方から「http://bank.org/rel/transfer
」のリンクと「edit
」の関係からURIを抽出します。そして、そのURIに対しPOSTリクエストを送信します。
POST /transfers Host: bank.org Content-Type: application/vnd.bank.org.transfer+xml;charset=UTF-8 <transfer xmlns="urn:org:bank:accounts"> <from>account:AZA12093</from> <to>account:ADK31242</to> <amount currency="USD">100</amount> <note>RESTing</note> </transfer>
この場合も同様に、Content-Type
の値に注意してください。
口座振替を開始した後、サーバーは以下を返します。
201 Created Content-Type: application/vnd.bank.org.transfer+xml;charset=UTF-8 <transfer xmlns="urn:org:bank:accounts"> <link rel="self" href="http://bank.org/transfer/XTA8763"/> <link rel="http://bank.org/rel/transfer/from" type="application/vnd.bank.org.account+xml" href="http://bank.org/account/AZA12093"/> <link rel="http://bank.org/rel/transfer/to" type="application/vnd.bank.org.account+xml" href="http://bank.org/account/ADK31242"/> <link rel="http://bank.org/rel/transfer/status" type="application/vnd.bank.org.status+xml" href="http://bank.org/check/XTA8763"/> <id>transfer:XTA8763</id> <amount currency="USD">100</amount> <note>RESTing</note> </transfer>
Step 4:口座振替の状態を検索するために、クライアントは、関係「http://bank.org/check/XTA8763
」のリンクからURIを抽出することができ、それに対してGETリクエストを送信します。
インタラクションの状態をカプセル化するためのコンテキスト依存のリンクを持った表現を使用することで、この実装がRESTfulになります。つまり、それがハイパーメディアがアプリケーション状態のエンジンとなるという制約の優位性を得ているのです。
さて、一歩離れて、インタラクションの新しいセットを実装するために必要となる情報をハイライトします。始めるにあたり、クライアントは口座を検索するためのURIを知る必要があります。次に、さまざまなリンクの関係の意味や名前を知る必要があります。さらに、それぞれのメディアタイプを知る必要もあります。それにより、実行時に、他の契約を動的に知ることができます。結果、私たちは以下の改訂ドキュメントを出すことができます。
Bank.OrgのAPI
URI
http://bank.org/accounts?findby=someparams
預金口座を検索するために、このURIでGETリクエストを送信します。
findby
のクエリーパラメータの値に、顧客ID、顧客名、顧客の社会保障番号を渡すことが可能です。このリソースはapplication/vnd.bank.org.accounts+xml
のメディアタイプをサポートします。リンクの関係
self
この関係とリンクのURIは、口座や振替リソースといった、リソースを含めて参照します。
http://bank.org/rel/transfer
andedit
これらの関係とリンクのURIは、新規の口座振替リソースを作成するのに使用します。
http://bank.org/rel/customer
この関係とリンクのURIは、顧客のリソースを取得するのに使用します。
http://bank.org/rel/transfer/from
この関係とリンクのURIは、振替元の口座リソースを識別します。
http://bank.org/rel/transfer/to
この関係とリンクのURIは、振替先の口座リソースを識別します。
http://bank.org/rel/transfer/status
この関係とリンクのURIは、リソースの状態を取得するのに使用します。
メディアタイプ
application/vnd.bank.org.accounts+xml
このメディアタイプの表現は、
urn:org:bank:accounts
の名前空間で宣言されたaccounts
ドキュメントを含みます。詳細はXMLスキーマを参照してください
application/vnd.bank.org.transfer+xml
このメディアタイプの表現は、
urn:org:bank:accounts
の名前空間で宣言されたtransfer
ドキュメントを含みます。詳細はXMLスキーマを参照してください。
application/vnd.bank.org.customer+xml
このメディアタイプの表現は、
urn:org:bank:customer
の名前空間で宣言されたtransfer
ドキュメントを含みます。詳細はXMLスキーマを参照してください。
application/vnd.bank.org.status+xml
このメディアタイプの表現は、
urn:org:bank:transfer
の名前空間で宣言されたstatus
ドキュメントを含みます。詳細はXMLスキーマを参照してください。
異なる種類の記述
私が前のセクションで示したRESTfullなアプリケーションを記述するためのアプローチには、ある興味深い特徴ばかりでなく多少おかしなところもあります。
WSDLとWADLをよく知っている人々のために、前のセクションでの説明は、型にはまらないように見えるかもしれません。すべてのオペレーションに対して入力と出力メッセージを記述する代わりに、私たちはメディアタイプを見ています。しかし、application/xml
のような一般的なメディアタイプは、顧客リソースや振替リソースの表現から口座リソースの表現を区別する手助けとして、あまりにも一般的すぎます。したがって、今回の例では、私はカスタムのメディアタイプを使用しました。これらのメディアタイプのそれぞれが「+xml
」で終わり、RFC 3023(サイト)に従って、それがXMLであるかのように、XMLのプロセッサ(XMLHttpRequest(サイト)を含む)はそれらの表現を処理することができます。そういったメディアタイプを見ることで、クライアントは口座リソースの表現を取得したのか、振替リソースの表現を取得したのかを知るのです。より重要なことは、その表現を取得するのに使用するURIの構造や構文について、何も責任を負う必要はありません。
さらに、アプリケーションが使っているすべてのURIをリストアップする代わりに、そのドキュメントにはクライアントがインタラクションを開始する必要のある口座振替のための唯一のURIを含んでいます。ここで留意すべき点は、違う例では、私たちは複数のドキュメントが必要かもしれません。これはできるだけ少ない数の事前公開が目的です。何故それがよりよいのでしょうか?それは実際のリソースのURIからクライアントを切り離し、クライアントは実行時までほかのURIを知る必要がないからです。
最後に、上記のドキュメントは、各々のURIに適用できるHTTPのオペレーションを含んでいませんでした。その代わり、私は、できるだけたくさんのオペレーションを見つけるのに、クライアントがそれぞれのURIについてHTTP OPTIONSを送信すると仮定しました。そして、リソースの表現を取得するためにHTTP GETを、リソース群の中に新しいリソースを作るためにHTTP POSTを、既存のリソース(あるいは、クライアントがリソースに対しURIを割り当てることができるならば作られたもの)を更新するためにHTTP PUTを、そして、リソースを削除するためにHTTP DELETEを使用します。
これをまとめると、RESTfullな契約を記述するには、以下が必要です。
- いくつかのURIを事前公開し、これらのURIに相当するリソースをドキュメント化してください。このリストの数はできる限り少ないものにしておいてください。これらのURIがアプリケーションに対する開始ポイントとなります。
- すべてのメディアタイプをドキュメント化してください。XMLベースの表現に対し、必要ならば、それぞれの表現の構造をドキュメント化するためにXMLスキーマを使用してください。
- すべてのリンクの関係をドキュメント化してください。
- 実行時に所定のURIでサポートされているHTTPオペレーションを見つけるために、クライアントにHTTP OPTIONSを使用させてください。場合によっては、リンクの関係の種類は、サーバーが与えられたオペレーションのサポートを決定するのに、クライアントに対して十分なものかもしれません。
そのような記述は、完全でもなく十分に機械が解釈できるものではありません。
それは単純に契約の静的な側面を含んでいるので、完全でありません。そして、リンクを通して実行時に可能なワークフローを記述することをサーバーに任せます。
RESTの利点についてすでに納得していて、HTTPを用いたRESTfulアプリケーションを積極的に構築している人たちにとって、完全に機械が解釈できる記述がないということは、問題ではないかもしれません。
しかし、SOAP、WSDL、WS-*を使用し、RPCに似たアプローチをとっている分散型アプリケーションを構築していて、RESTを熟考している人たちにとって、完全に機械が解釈できる記述がないということは、致命的問題のように思えるかもしれません。しかし、現在、人が存在するならば、 RESTfulな機械が解釈可能な記述を使用しておこなうことができる作業量は制限されます。これは、以下の理由からです。
- 契約の動的な性質:私が前のセクションの例で説明したように、表現はその中のリンクを使用することで、契約に関する動的な側面を記述します。表現の外側のXMLベースの機械が解釈可能な記述の中にある、このコンテキスト依存の契約を説明することは冗長です。
- メディアタイプの柔軟性:SOAPベースのアプリケーションとは異なり、RESTfulアプリケーションはXMLを使うことに限定されていません。それらは、スキーマ言語がない他のメディアタイプを使うことができます。
リモートインターフェースのための契約に関する完全に機械が解釈可能な記述は、間違った考えであることにも注意してください。 WSDLやWADLを使用して作られた機械が解釈可能な記述は、構造や構文のみを記述することができ、セマンティクスを記述することはできません。しかし、機械が解釈可能な記述は、時として、私たちがプログラマーとして、テスターとして、管理者としてする必要のある作業量を減らす手助けとなります。
私たちが統一インターフェースや契約の動的な側面を考慮に入れないならば、私たちは機械が解釈可能な方法で契約の残りを記述することができます。以下が例となります。この記述での私の意図は、クライアント-サーバーのインタラクションを監視やテストを希望するためのツールやフレームワークを支援するだけであることに注意してください。WSDLやWADLを模倣するものではありません。
<description xmlns:bank="urn:org:bank:accounts"> <types> <!-- Include the schema used for all representations --> <include href="bank-schema.rng"/> </types> <!-- List all media types and the corresponding XML types --> <media-types> <media-type> <name>application/vnd.bank.org.accounts+xml</name> <representation>bank:account</representation> </media-type> <media-type> <name>application/vnd.bank.org.transfer+xml</name> <representation>bank:transfer</representation> </media-type> ... </media-types> <relations> <relation> <documentation>This relation ...</documentation> <name>http://bank.org/rel/transfer</name> </relation> ... </relations> <resources> <resource> <name>accounts</name> <media-type-ref>application/vnd.bank.org.accounts+xml</media-type-ref> <uri> <!-- This is optional --> <base>http://bank.org/accounts</base> <params> <param> <documentation>Use this parameter to ...</documentation> <name>findBy</name> </param> </params> </uri> </resource> <resource> <name>transfer</name> <media-type-ref>application/vnd.bank.org.transfer+xml</media-type-ref> </resource> ... </resources> </description>
これは私が前のセクションで記述したもので、機械が解釈可読なバージョンです。そして、これは確実にどの標準にも準拠していません。私たちは、今なおアプリケーションのセマンティクスを記述する必要があるので、この記述により人が理解可能な記述の必要性がなくなったわけではありません。
この説明での重要な部分をハイライトします。
- スキーマタイプ: この例では、すべての表現にXMLの使用を選択したので、私はスキーマの利用への言及を含めました。選択した表現形式がスキーマによって記述可能でなければ、このセクションは意味のないものとなったでしょう。
- メディアタイプやそれに対応するXMLドキュメントを利用する。
- リンクの関連すべてを列挙する。
- リソースの名前とそれらのメディアタイプ(その名前がURIではないことに注意してください)
- アプリケーションの開始ポイントを提供するこれらのリソースに対するURI
この種の記述は、人間が理解可能な記述より有効でしょうか?そのような記述を解釈することができるツールやフレームワークがないので、答えはnoかもしれません。
これは実用的ですか?
あなたがWADLドキュメントのような機械が解釈可能な契約をベースとしたサーバーサイドのコードとクライアントサイドのコードを書いているならば、コーディングの流れは以下の通りかもしれません。
- 記述からリソースクラスを生成します。それぞれのリソースクラスは、潜在的にその記述のURIに対応しています。
- 表現に結びつくクラスを生成します。その表現がXMLベースならば、私はさまざまなXMLドキュメントに対応したクラスを生成するでしょう。
- さまざまなHTTPオペレーションに対応するクライアントサイドのスタブを生成します。
- コーディングを開始します。
このモデルでは、契約のRESTfulな記述に対して機能しません。そのステップは、違うものとなります。
- すべてのメディアタイプに関する記述を読みます。メディアタイプがXMLスキーマを使用して記述されるならば、そのスキーマを手に入れ、XMLをパース、あるいは生成することのできるクラスを生成します。
- すべてのリンクの関係に関する記述を読みます。
- リソースクラスを手作成します。
- クライアントが表現を受け取るときはいつでも、表現からデータを抽出することに加えて、リンクを探します。あなたが既知の関係と共にリンクを見つけるならば、後に使用するために、hrefやtype属性(存在するなら)を抽出します。
- クライアントサイドでは、あなたが実行したいと思うオペレーションがサーバーでサポートされているかを確認するために、HTTPリクエストを送信する前に、最初にHTTP OPTIONSリクエストを送信します。問題なければ、あなたのクライアントアプリケーションでそのオペレーションが可能となるようにします。
私が知っているほとんどのソフトウェアフレームワークは、共通インターフェースやリソースクラスのための慣例など、上記ステップのいくつかを扱うことができ、選択したプログラミング言語に依存し、XMLを作成したりパースするためのクラスを生成することができます。しかし、残りは開発者に委ねられます。さらには、これらのフレームワークのほとんどが、サーバーサイドの開発に重点を置いています。そして、既存のHTTPクライアントのライブラリが十分なものであるという仮定のもと、クライアントサイドの開発を除外しています。その結果、あなたは上記の(4)と(5)を処理するためのカスタムコードを作成する必要があるかもしれません。
テストや契約を実行するためのソフトウェアツールについてはどうですか?実行時に以下をおこなうために、上記の機械が解釈可能な記述を読むためのソフトウェアを作成することは可能です。
- 表現のメディアタイプがあらかじめ定義されていることを確認します。
- 表現がメディアタイプのあらかじめ定義された記述にマッチすることを確認します。
- 表現に含まれるすべての関連には、あらかじめ定義された関係とメディアタイプがあります。そして、そのURIは後に続く事前定義されたURIのパターンを含んでいます。
私は、このようにしてこれらを確認することができるソフトウェアを全く知りません。しかし、機会はたくさんあります。あなたがこの記事をここまで読んだのならば、あなたはそれらの機会が何であるかが分かっています。
結論
本稿における私の目的の一つは、WSDLやWADLのような伝統的な契約に関する記述が、RESTful なアプリケーションの記述に適していないという事実を示すことです。私が口座振替の例で示したように、契約の一部だけは静的に記述することができますが、残りについては動的でコンテキスト依存です。クライアントは、リンクを見ることで実行時にその契約の動的な部分を追うことができます。設計時やテストの目的でいくつかの機械が解釈可能なドキュメントを通して構造を記述しようとすることができます。しかし、サーバーが残りを実行時に記述することで、クライアントとサーバー間の結合度を大きく減らします。静的に完全な契約を記述しようとすることは、表現の外側ですべてのコンテキスト依存のリンクを複製することに等しいです。
対照的に、WSDLやWADLのような記述言語は、コンテキストのない方法で契約を記述しようとします。そして、クライアントの開発者は、これらの記述で書かれたさまざまなメッセージ交換パターンからクライアントアプリケーションを構築するための方法を知るためにユーザードキュメントに委ねます。 RESTfulなアプリケーションでは、サーバーはこの情報をリンクの形式で実行時に提供します。
まとめると、RESTfulアプリケーションは契約をもっています。私たちは、単純に、何を探すべきか、どこを探すべきかということ、そして、その契約がコンテキスト依存であることを覚えておいてください。
著者について
SubbuはYahooに勤めています。彼についてより知りたければ、彼のブログ(ブログ)を参照してください。