BT

RESTに関する疑問に答える

| 作者 Stefan Tilkov フォローする 3 人のフォロワー , 翻訳者 松本 清一 フォローする 0 人のフォロワー 投稿日 2008年4月21日. 推定読書時間: 20 分 |

相も変わらず、REST(source)についての学習は、特定のシナリオに対して実際にその概念がどのくらい適用可能であるかということを疑問に思うことに落ち着くと言えるでしょう。そして、あなたがおそらく全く異なるアーキテクチャのアプローチに慣れているだろうとすると、RESTに疑問を持ち始めた状態、あるいはRESTfulなHTTPを気に入り、実際に本当に動かしている状態、あるいは「Hello, World」レベルの導入を終えたまま、単に中断している状態であるというのは、ごく自然なことでしょう。本稿では、RESTを探求しようとしている、特に、SOAP/WSDLベースのWebサービスを背景としたアーキテクチャのアプローチにおいて多くの経験があるときに、RESTについて抱く最も一般的な10の疑問について答えようと思います。

1.RESTはCRUDに適しているが、「真の」ビジネスロジックには適していない

これは、RESTのメリットについて疑念を抱く人たちの間に見られる最も一般的な反応です。結局のところ、利用できるものの全てが登録/参照/更新/削除であるならば、より複雑なアプリケーションの動作をどうやって表現するのでしょうか?私は、RESTシリーズの導入記事(参考記事)の中で、これらの懸念のいくつかについて解決しようとしましたが、この点についてはより精密かつ正確な議論をする価値があります。

まず初めに、HTTPの操作にはGET、PUT、POST、DELETEがありますが、CRUDデータベース操作と1:1のマッピングを持っていません。例えば、POSTとPUTの両方は、新しいリソースを作るのに使用されます。POSTが「コレクション」あるいは「ファクトリー」のリソースに発行され、 URIを割り当てるのはサーバーのタスクであるのに対し、PUTはリソースのURI(それは更新か登録です)を決定するのがクライアントである点が異なります。しかし、いずれにせよより複雑なビジネスロジックをどのように扱うのかという問題に立ち返ります。

 c を返す任意の計算 calc(a, b) は、URIに変換することができ、それは結果を特定します。例えば、x = calc(2,3) は、http://example.com/calculation?a=2&b=3となるかもしれません。一見、RESTful HTTPの良くない誤用であるように見えます。つまり、リソースを特定するためにURIを使用しておらず、操作ではないのか?ということです。その通りですが、実際はそれが私たちがすべきことです。http://example.com/sum?augend=2&addend=3は、リソースを特定しており、つまりは2と3を加えた結果です。そして、今回の(明らかに作られたような)例では、結果を得るためにGETを使用するということは、良い考えのように思います。結局、キャッシュすることができ、それを参照し、計算することができることで、おそらく副作用がなくコストのかからないものとなります。

もちろん多くにおいて、大部分のケースとまではいかないまでも、何かを計算するためにGETを使うことは、間違ったアプローチであるかもしれません。GET が「副作用のない」オペレーションであることを期待されていることを思い出してください。つまり、GETの発行でリンクをたどることが行っていることの全てなら、クライアントは(サービスに対して何かをしなければならないといった)責務を少しも引き受けないか、少しの責任も負いません。それ故、その他多くのケースにおいて、POSTを通して新しいリソースを作成できるように入力データをサーバーに与えることは、より合理的なことです。そのレスポンスで、サーバーは結果のURIを示すことができます(そして、おそらくあなたをそこへ連れていくためにリダイレクトを発行するでしょう)。その結果は再利用可能で、ブックマークができ、それが取得されたときにキャッシュすることができます。基本的には、このモデルを結果をもたらす全てのオペレーションへと拡張することができるのです。つまり、それはあなたが考えうることのできるすべてと言っても過言ではありません。

2. 公式の契約や記述言語が存在しない

RPCからCORBA、DCOMからWebサービスでは、オペレーション、それらの名称、入出力パラメータの型を記載するためのインターフェース記述がありました。RESTは、インターフェース記述言語無しで大丈夫なのでしょうか?

 

非常によく尋ねられるこの質問に対して、3つの回答があります。

 

まず第一に、(非常によくある選択ですが)XMLと一緒にRESTful HTTPを利用する場合、DTD、XMLスキーマ、RELAX NG(サイト・英語)、Schematron(サイト・英語) といったXMLスキーマ言語の世界全体をいつでも利用することができます。通常、WSDLを使用して記述していることの95%は、ほぼ間違いなくWSDL とは全く関係のないもので、どちらかと言えば、あなたが定義したXMLスキーマの複合タイプに関係があるものです。WSDLが一番に加えるものは、普通はオペレーションやその名称に関連するものです。そして、それらを記述することで、RESTの統一インターフェースはとてもつまらないものとなります。結局、GET、PUT、POST、DELETEが、オペレーションの全てなのです。XMLスキーマの利用について言えば、たとえRESTfulインターフェースを利用するとしても、自身が選択した言語のためのデータバインディングコードを生成するために、あなたのお気に入りのデータバインディングツール (もし持っているなら)が利用できるということなのです。(これは完全な回答ではありませんので、以降を読んでください。)

第二に、何のために記述が必要なのかということついて、あなた自身に尋ねてください。最も一般的なのは(それだけではありませんが)、ある記述を持つための利用ケースとして、記述しているインターフェースのスタブとスケルトンを生成することです。通常、それはドキュメントではないです。故に、WSDLフォーマットのような記述には、オペレーションの動作についての説明は何もありません。単に、それは名称の一覧です。呼び出し方を知るために、人が読むことのできる何かしらのドキュメントが必要となります。一般的なRESTアプローチでは、あなたが提供しようとしているものがHTML フォーマットのドキュメントで、場合によってはリソースへの直接のリンクが含まれています。複数の表現を持つというアプローチを利用することで、自己文書化されているリソースを得る可能性も十分にあります。つまり、ブラウザからリソースへのHTTP GETを行うだけで、実行可能なオペレーション(HTTPの操作)、受け入れ/配信するコンテントタイプのリストだけでなく、データを含んだHTMLドキュメントを得ることができるのです。

第三に、RESTfulサービスに対し記述言語の使用を強く主張するのならば、Web Application Description Language (WADL)(source)か、制限付きのWSDL 2.0(source)(作成者によればRESTfulサービスの記述も可能であるということです)を利用することもできます。WADLとWSDL 2のどちらもハイパーメディアを記述するのに実用的でないにも関わらず、これがRESTの中核となる側面の一つです。そうだとしても、私はそれらが十分に実用的であるとはとても思えません。

3. 実際、誰がアプリケーション実装の内部の多くを公開したいと思うのか?

その他の一般的な関心事として、リソースはあまりに低レベルであるということです。言い換えれば、実装の詳細を公開すべきではないということです。結局、クライアント(コンシューマ)で意味のある何かを行うためにリソースを使用することに関して、負担を課しているのではないでしょうか?

簡単に答えれば、ノーです。リソースのGET、PUT、あるいはその他全ての手法による実装は、「サービス」あるいはRPCのオペレーションの実装と同様に、簡単であるか複雑かのどちらかとなるでしょう。RESTの設計の原則を適用することは、基礎を成すデータモデルから、特定の項目を公開しなければならないということを意味しています。即ち、オペレーションセントリックな方法でビジネスロジックを公開するのではなく、データセントリックな方法であるということです。

関連する関連事として、リソースへの直接アクセスを可能としないことで、セキュリティを強化することができるということです。これは、「隠すことによるセキュリティ」として知られている古い間違った考えをベースとしています。実際、それは逆効果であると主張する人もいます。アプリケーション固有のプロトコルでアクセスする特定のリソースを隠すことによって、それらを保護するためのインフラを簡単に利用することができなくなってしまいます。固有のURIに意味のあるリソースを割り当てることによって、異なるリソースに対して別々に動作するように、例えば、Apacheのセキュリティルールを利用する(ロジックの書き直し、ロギング、統計なども同様)といったことが可能です。これらを明確にすることで、セキュリティは低下せず、強化します。

4. RESTはHTTPでのみ動作し、トランスポートプロトコル非依存ではない

まず初めに、HTTPがトランスポートプロトコルではなく、アプリケーションプロトコルであるということを一番に強調します。それは、下層にあるトランスポートとしてTCPを使用しますが、それを超えたものがあります(でなければ、それはほとんど利用されないでしょう)。単なるトランスポートとしてHTTPを利用するということは、HTTPの誤用です。

次に、抽象化は必ずしも良い考えでありません。Webサービスは、単一の抽象レイヤーの下に、多くの非常に異なる技術を隠蔽しようとするアプローチを採用しています。しかし、抽象化が崩れる傾向にあります。例えば、JMSを通して、あるいはHTTPリクエストとしてメッセージを送信する間には大きな違いがあります。最小公分母に至るまで広く異なるオプションを抽象化しようとすることは、誰の役にも立ちません。共通点は、共通APIの下にあるリレーショナルデータベースやファイルシステムを隠蔽するための共通の抽象概念をつくることでしょう。もちろんこれは可能ですが、クエリーに対処しようとするとすぐに、抽象化が問題へと変わります。

最後に、Mark Baker氏が、かつてこう言いました。「プロトコル非依存はバグで、特徴ではない」。このことは初めは奇妙に思いましたが、本当のプロトコル非依存は、成し遂げるのが不可能であるのではないかということを考える必要があります。つまり、異なるレベルであるかどうかということで、別のプロトコルに依存することを決められるというだけです。HTTPのように、広く認められ、公式に標準化されたプロトコルに依存することは、全く問題ではありません。HTTPがそれを置き換えようとするための抽象概念よりも広く知られサポートされているのであれば、それが正に真実です。

5. RESTfulアプリケーションを設計する方法に関して、実用的で、明確かつ一貫性のあるガイダンスがない

「公式」なベストプラクティスが無い、RESTの原則に沿った方法でHTTPを利用して特定の問題を解決するための標準的な方法が無いというように、 RESTfulな設計については、多くの側面があります。良くなっていることに疑いの余地はありません。さらに、RESTはWSDL/SOAPベースの Webサービスよりもより多くのアプリケーション概念を具体化しています。言い換えれば、この批判がそれに多くの価値を与えている間は、別の選択肢としてとして非常に適しています。(基本的に、ガイダンスを全く示していません)

時折、「RESTの専門家でさえ、どうすべきかについて合意することができない」という形でこの疑問が発生します。一般に、それは真実でありません。例えば、数週間前にここ(参考記事・英語)で述べた核となる概念が、RESTコミュニティ(そのようなものがあるという前提で)の全てのメンバーによって議論されていない(される気配もない)のではないかと思いがちです。しかし、それがとりわけすばらしい記事ということではなく、以前に人々が基礎より少し多くのことを学んだので、多くの共通理解があるというだけの理由です。もし試してみる機会があるのなら、5人のSOA支持者に何かを議論させることが、5人のREST支持者にそうさせることよりも容易であるかどうかを試してみてください。多くのSOAとRESTのディスカッショングループに長いこと参加した過去の経験に基づいて、私はRESTの人たちお金をかけるでしょう。

6. RESTはトランザクションをサポートしていない

一般に、人々がトランザクションについて話すとき、「トランザクション」という言葉はかなり過剰であり、それはデータベースのACID特性のことを言っています。SOA環境においては、WebサービスをベースにしているかHTTPだけをベースにしているかどうかによらず、それぞれのサービス(あるいはシステムやWebアプリケーション)の実装は、トランザクションをサポートしているデータベースと協調しています。明示的にトランザクションを生成するような場合を除いて、ここに大きな変化はありません(EJBコンテナ、もしくは、トランザクション生成を操作する別の環境でサービスが動作しない限り)。複数のリソースと協調する場合は、同様のことが言えます。

トランザクションをより大きな単位で結合する(あるいは望むのであればそれをつくる)時点で、事情が異なり始めます。Webサービス環境では、人々が2台のPCでやっていたことと同じように振舞うようにするための選択肢が少なくともあります。例えば、Java EE環境ではWS-Atomic Transaction (source)(WS-AT)としてサポートされています。それはWS-Coordination(source)ファミリーの標準の一つです。本来、WS-ATはXAによって指定された2つのPCのプロトコルと同じものあるいは非常に良く似たものを実装します。これは、トランザクションコンテキストがSOAPヘッダーを使用して伝播されることを意味しています。そして、実装は既存のトランザクションへリソースマネージャーのフックとなるように注意します。基本的には、EJB開発者が行っていることと同じモデルが使用されます。分散トランザクションがローカルトランザクションと同じようにアトミックに振舞うのです。

むしろ反対に、SOA環境での原子トランザクションについては、言うことがたくさんあります。

  • 疎結合とトランザクション、特にACID特性のそれらは、単純にマッチしません。複数の独立したシステムにわたってコミットを調整しているというまさにその事実が、それらをとても密に結合しています。
  • この調整をすることができるということは、サービス全体に対して集中管理を必要とします。それは非常に疑わしく、おそらく、会社の境界を越えた2台のPCを実行することもできないでしょう。
  • これをサポートするために必要とされるインフラは、通常、非常に高価かつ複雑です。

ほとんどの場合、SOAまたはREST環境のACIDトランザクションで必要なのは、実際には設計センスです。つまり、おそらくあなたのサービスあるいはリソースが間違った方向にモデル化していると思います。もちろん、原子トランザクションは、単にトランザクションの一種です。疎結合システムに対してより適しているであろう拡張トランザクションモデルがあります。しかし、まだ採用されているのを見たことがありません。それは、Webサービスの分野でもありません。

7. RESTは信頼できない

RESTful HTTPに対するWS-ReliableMessaging(参考記事・英語)に相当するものが無いとよく指摘されます。そしてその理由から、多くの人たちは信頼性が問題となるところでは適用できないと結論づけます(その問題は、ビジネスシナリオに関連するほぼ全てのシステムにあてはまります)。しかし、多くの場合、あなたが必要としているものは、メッセージの配信を制御するインフラのコンポーネントではありません。どちらかといえば、メッセージが配信されたのかどうかを知る必要があります。

一般的に、レスポンスメッセージを受け取ること(HTTPの場合では、単純な200のOK)は、あなたが知っている通信相手がリクエストを受け取ったということを意味します。つまり、レスポンスを受け取らないときに問題は発生します。リクエストが相手に届かなかったのか、あるいは届いた(結果として何らかの処理が行われた)のかは分かりませんが、レスポンスメッセージが失われた状態です。

リクエストメッセージが相手側に届いたことを確かなものとするための最も簡単な方法は、それを再送することです。受け手が再送に対処できる(例えば、それを無視するとか)のであれば、それはもちろん可能です。この機能は、冪等と呼ばれます。HTTPは、GET、PUT、DELETEが冪等であることを保証します。そして、あなたのアプリケーションが正しく実装されているのであれば、クライアントは、レスポンスが受け取れなかったリクエスト全てに対して、単純に再リクエストすることができます。POSTメッセージは冪等ではありませんが、少なくともそれはHTTPの仕様書にそういったことは書かれていません。よって、あなたにはいくつもの選択肢が与えられます。(その処理がPUTに対応づくのであれば)PUTを使用してJoe Gregorio氏による共通のベストプラクティスを活用する(source)のか、これを標準化しようとする現行の提案(Mark Nottingham氏のPOE, Yaron Goland氏のSOA-Rity(source), Bill de hOra氏のHTTPLR(source)など)のいずれかを採用するのか、どちらかを選ぶことができます。

個人的には、ベストプラクティスアプローチの方が好きです。すなわち、信頼性の問題をアプリケーション設計の面に変えてください。しかし、これに関する意見はかなり異なります。

これらのソリューション全てが、信頼性の問題の大部分を解決しているので、HTTPリクエストとレスポンスのシーケンスに対する配信順序といった、配信保証をサポートするといったことは必要ありません。それにも関わらず、多くの現行のSOAP/WSDLが、WS-Reliableメッセージの無いものや、過去に作られた多くのものであり、指摘に値するように思います。

8. パブリッシュ/サブスクライブをサポートしていない

REST は、基本的にクライアントサーバーモデルをベースにしています。そして、HTTPは通信のエンドポイントとしてクライアントとサーバーを参照します。クライアントは、リクエストを送信しレスポンスを受信することによってサーバーと相互に作用します。パブリッシュ/サブスクライブモデルでは、利害関係者が特定の情報カテゴリにサブスクライブし、新たに何かが起こるたびに通知を受け取ります。RESTful HTTP環境では、パブリッシュ/サブスクライブはどのようにサポートされるのでしょうか?

このことに関する完璧な例をみるために、遠くまで探しに行く必要はありません。それは、シンジケーションと呼ばれているもので、RSS(source)やAtomシンジケーション(source)がその例です。クライアントは、新しい情報のために、変更の一群を表現するリソースに対するHTTPを発行することにより問い合わせを行います。例えば、特定のカテゴリや時間間隔をおいて行います。これは非常に効率の悪いように思えますが、そうではありません。何故なら、GETはWebで最も最適化されたオペレーションだからです。実際、人気のあるWebログサーバーが、サブスクライブしているクライアントそれぞれに個々の変更を積極的に通知をする必要があるのなら、より一層のスケールアップをするであろうということは簡単に想像することができます。ポーリングによる通知は、大きくスケールします。

あなたのアプリケーションリソースにシンジケーションモデルを拡張することができます。例えば、顧客リソースや予約の証跡の変更に対するAtomフィードを提供します。さらに、基本的には無制限のサブスクライブの数をアプリケーションで対応可能とし、フィードリーダーでそれらのフィードを参照することができ、ブラウザでリソースのHTML表現を参照するのと同じようにします。

もちろん、これはいくつかのシナリオに対しては適切な回答でありません。例えば、リアルタイム性が要求されるソフトは、この選択は除外され別の技術がより適切であるかもしれません。しかし、多くの場合、疎結合の混成、シンジケーションモデルにより可能となるスケーラビリティと通知は、非常に適しているでしょう。

9. 非同期インタラクションがない

与えられたHTTPのリクエスト/レスポンスモデルで、どうやって非同期通信を行うのでしょうか? さらに、私たちは、非同期について話すとき、一般に意味するところは複数あるということを認識する必要があります。プログラミングモデルについて言及すると、ワイヤの相互作用とは無関係にブロッキング、あるいはノンブロッキングすることができます。それはここでの関心事ではありません。しかし、処理が2、 3時間かかるかもしれないリクエストをクライアント(コンシューマ)からサーバー(プロバイダ)にどうやって配信するのでしょうか? コンシューマはその処理が完了したことをどうやって知るのでしょうか?

 HTTP には、固有のレスポンスコード202(受け入れられた)があり、その意味は、"そのリクエストは処理を受け入れた。しかし、処理はまだ完了していない。" として定義されています。これは、明らかに私たちが探しているまさにそのものです。結果については、複数の選択肢があります。まず、クライアントが結果にアクセスするためにGETするリソースのURIを、サーバーが返すことができます。あるいは、サーバーが一度完了した結果をPOSTすることを期待する URIを、クライアントが含めることもできます。

10. ツール不足

最後に、人々はRESTful HTTP開発をサポートするために利用可能なツールの不足について文句を言います。2で示したように、データの面に関してこれは真実ではありません。それがメソッドやそれらを呼び出す方法の数と直交した関心事であるように、以前使っていたデータバインディングやその他のデータAPIの全てが利用可能です。プレーンなHTTPとURIのサポートという点では、間違いなく、地球上にある全てのプログラミング言語、フレームワーク、ツールキットが、それぞれの形でそれらをサポートしています。最後に、ベンダーは自身のフレームワークでのRESTful HTTP開発に対し、より一層簡単で優れたサポートを行っています。例えば、SunのJAX-RS (JSR 311)、マイクロソフトの.NET 3.5やADO.NETデータサービスフレームワークによるRESTサポートがあります。

結論

REST、最も一般的な実装はHTTPで、それは完璧なのか? もちろん違います。完璧なものなどなく、全てのシナリオに対して存在するわけでもなく、その大部分が単一のシナリオのためにあるわけでもありません。私は、より複雑な回答の必要がある多くの非常に的確な問題分野について無視してきました。例を挙げれば、メッセージベースのセキュリティ、部分アップデート、バッチ処理などです。私は、今後の連載の中でこれらについて解説することを心から約束します。私は、あなたが抱いていた疑問のいくつかを解決できたことを期待しています。もし私がとても重要なことを見逃していたとしても、あなたがコメントが何のためにあるのかを知っているので大丈夫でしょう。

Stefan Tilkov氏は、InfoQのSOAコミュニティのリードエディタであり、共同創設者です。ドイツとスイスを基盤とした innoQの主席コンサルタントとRESTafarianのチーフです。

原文はこちらです:http://www.infoq.com/articles/tilkov-rest-doubts

この記事に星をつける

おすすめ度
スタイル

こんにちは

コメントするには InfoQアカウントの登録 または が必要です。InfoQ に登録するとさまざまなことができます。

アカウント登録をしてInfoQをお楽しみください。

あなたの意見をお聞かせください。

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

このスレッドのメッセージについてEmailでリプライする
コミュニティコメント

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

このスレッドのメッセージについてEmailでリプライする

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

このスレッドのメッセージについてEmailでリプライする

ディスカッション

InfoQにログインし新機能を利用する


パスワードを忘れた方はこちらへ

Follow

お気に入りのトピックや著者をフォローする

業界やサイト内で一番重要な見出しを閲覧する

Like

より多いシグナル、より少ないノイズ

お気に入りのトピックと著者を選択して自分のフィードを作る

Notifications

最新情報をすぐ手に入れるようにしよう

通知設定をして、お気に入りコンテンツを見逃さないようにしよう!

BT