yohei-y:weblog

XML と REST/Web サービス関連の話題が中心の weblog です

2005-05-30

REST 入門(その10) 終わりに

» REST 入門 目次

前回まで、REST 入門ということで、 REST アーキテクチャスタイルとは何なのか、 について基礎的なところを結構細かく :-) 説明してきました。 REST 入門はこれで終わりですが、最後にロイ・フィールディングの論文から REST アーキテクチャスタイルの各制約を抜き出して説明します。

Null スタイル
最初は、制約がまったくないところからはじまります。それが Null スタイルです。
クライアント・サーバ
最初の制約はクライアント・サーバです。REST がクライアント・サーバから派生していることは、 "2. アーキテクチャスタイルとは" で解説しました。
ステートレス
REST スタイルにおいて、サーバはクライアントの状態を管理しません。すべての状態はクライアントで持ちます。 クッキーでの状態管理が REST でないことは "8. REST でないもの" で説明しました。
キャッシュ
REST スタイルではサーバが返す結果をクライアントでキャッシュ可能なように設計します。 これによりネットワーク効率を向上させることができます。
統一インターフェース
REST の制約で最も特徴的なのがこの統一インターフェースです。 クライアントはどんなシステムとでも同じインターフェースで接続できます。 統一インターフェースについては "4. HTTP GET -- その絶大な効果"と "5. 四つの動詞 -- GET, POST, PUT, DELETE"で説明しました。
階層化システム
このシリーズでは説明しませんでしたが、REST スタイルの制約にシステムを階層化できることがあります。 これにより、たとえばロードバランサーでの負荷分散や、レガシーシステムのラッピング、proxy サーバなどが可能になります。
コードオンデマンド
この制約も説明していません。 REST では、クライアントがコードをサーバからダウンロードして実行することができます。 たとえば Javascript ですね。ただし、この制約はオプションです。

終わりに

僕がこの REST 入門シリーズを書いた目的は二つあります。 ひとつは「目次」で書いたとおり、日本語での REST の基礎的な資料を作るためです。 日本では Amazon Web サービスの REST API のような単純な XML over HTTP としてしか REST が認識されておらず、 往々にして間違った議論がされていたり、あるいはアーキテクチャスタイルとしての REST が注目されていなかったりします。 しかし REST は Web における次の5年の(もっとか?)基盤技術であると、僕は思っています。 各個人がどう評価するかはともかく、REST を知らずに Web を語ったり議論したりするのは非常に危ういと思うのですね。 そういう意味で、REST 周辺の言葉を整理して (Architectural Style の日本語訳も悩んだのです)、 日本でもちゃんと話ができるようにしたかった。 結果としては naoya さんに紹介してもらって僕の weblog のページビューも10倍くらいになりましたし、 WWW2005 後くらいから REST で検索してくる人が非常に多くなったので、 このシリーズをやってよかったなと思ってます。

もうひとつ、僕が言いたかったことは、せめて技術者が技術に接するときは純粋にそれを技術として評価しよう、ということです。 SOAP や WS-* の世界は、ベンダの対立など半ばゴシップ的な記事が IT 系ニュースサイトの紙面を躍らせるので、 どうしても脊髄反射的に「だから WS-XX は駄目なんだ」とか言いたくなるのですが、それは変なんですよね。 WS-* は確かに重くてすべてを理解するのは大変なんですけど、 Microsoft や IBM が無意味にあんなにリソースを割いて推進するわけがないのです(ハロウィン文書の例の戦略だ、というハナシもありますが)。

たとえば WWW2005 のパネルで SOAP/WS-* を厳しく批判していた Tim BrayAdam Bosworth は SOAP/WS-* のことを何も知らずに批判しているわけではないのです。 むしろ、知っているからこそ批判できるんです。 SOAP/WS-* 側の人間にしても同じです。 Don BoxJeffrey Schlimmer, Dare Obasanjo, Tim Ewald, Dave Orchard みんな REST のことはきちんと知っている。 だいたい Dave Orchard と Tim Bray なんてランチしてたりするし、 その他の人々も W3C のメーリングリストやミーティングなんかでちゃんと交流して議論しているわけです。 そういえば Tim Bray だって昨年の XML Developers' Conference (Microsoft よりのカンファレンス)で講演してました。

とまあ、僕も偉そうなこと書いてる割に REST をきちんと評価したのは昨年の8月くらいだったりします。 それまでは Web サービス = SOAP/WSDL で RPC だったんですが、 document/literal になってからイマイチわからなくなってしまった。 で、いろいろ調べたり考えたりしてやっと REST にたどり着きました。 「REST は XML の王道」とかキャッチーなことも書いてますが、 REST 万歳、SOSP/WS-* ダメダメと言うつもりはなくて、 両方ちゃんと評価しよう、ということです。

この weblog の今後ですけど、シリーズものだと普段はあまり気が乗らない基本的なことも書く気がおきてよい感じなので、 もう一回やってみようかと思ってます。 題材は今話題の(?) Web 2.0 にするつもり。 ではまた。

ラベル: ,

2005-05-28

REST 入門(その9) REST と SOAP

» REST 入門 目次

前回、WWW のうち REST アーキテクチャスタイルに従っていないものについて解説しました。 今回は「その筋」では有名な REST と SOAP の対決の概略を解説します。

Google で "REST vs SOAP" あるいは "SOAP vs REST" を検索すると、 たくさんの Web ページが見つかります。 いろいろな立場の人が、それぞれの意見を述べ合っていて、 ここで全ての主張や意見を解説するのは不可能です。 これから解説する内容は、あくまでも個人の意見ということをご了承ください(まー weblog なんてそんなもんですが)。

ところで最初からこんな話をするのもアレですが、 REST と SOAP は比べられるものなのでしょうか。 REST はこれまで何度も述べてきたとおり、ネットワークシステムのアーキテクチャスタイルです。 一方で SOAP はプロトコル、あるいはメッセージのエンベロープ形式です。 二つを比べようにもあまりに次元が違い過ぎます。 この二つが並べて議論されるとき、たいていは SOAP を拡大意解釈するか、 あるいは REST を縮小解釈しています。 たとえば Amazon Web サービスの SOAP API と REST API を比べたり(REST の縮小解釈)、 あるいは SOA と REST を比べたり(SOAP の拡大解釈)。 これには歴史的理由がいろいろあって、紆余曲折してきているというのが真相です。 ここでは時系列に沿って、REST vs SOAP を振り返ってみたいと思います。

SOAP RPC と REST

2000年ごろ、Web サービスといえば SOAP/WSDL/UDDI でした。 SOAP には何種類かの使い方があるのですが、 このころは SOAP エンコーディングを使った RPC (SOAP-RPC)が主流の使い方でした。 SOAP-RPC がやりたいこと(できること)は非常に単純です。 異なるプラットフォーム同士で RPC をすることです。

プラットフォームが異なる場合、標準的なデータフォーマットが必要となり、そこに SOAP エンコーディングという XML を採用したプログラム言語のデータ構造のシリアライズ形式が使われました。 SOAP エンコーディングを使った RPC は WSDL の記述の仕方から rpc/encoded と呼ばれます。

SOAP-RPC は便利です。それまで RPC がなかなか実現できなかったところで RPC が可能になりました(たとえば UPnP)。 しかし、SOAP-RPC は結局のところ RPC ですから、それ以前の RPC や DCOM, CORBA などの分散オブジェクト技術が持っていた問題をそのまま受け継ぐことになります。 サービスの呼び出し単位は細かく、オブジェクトが状態を持ちがちなので、スケーラビリティが問題になります。 そのような理由から SOAP のトレンドは SOAP-RPC から別のものに移っていくことになります。

WS-*/SOA

rpc/encoded よりも粒度が粗く、RPC でなく XML をそのままメッセージとして送信する、 そんな SOAP のやり取りを document/literal 形式といいます。 これは引数が DOM の Document オブジェクトひとつのメソッドを思い浮かべればいいでしょう。 XML を DOM でそのまま渡して、結果も DOM で返ってくる。 非常に単純化するとそんな形式です。

一方で SOAP の世界には WS-* と呼ばれる仕様群が登場します。 SOAP 自身は前にも述べたとおり単なるメッセージエンベロープ形式であり、 実際の運用ではさまざまな機能をその上に実装する必要があります。 各社バラバラにそれらの機能を作っていってもいいのですが、 ある程度共通化して使える機能に関して WS- という接頭辞をつけた名前の仕様書がさまざまなベンダから提案されました(されています)。 具体的な仕様書名を挙げれば、たとえば WS-SecurityWS-Addressing などです。

この WS-* 仕様群には、ベンダ各社の標準化競争だとか、 オーバースペックだとか CORBA の再来だとか、 さまざまな問題が指摘されています。 が、まあここではそういう話はおいておいて、純粋に技術的にどうなのかという議論をしたいと思います。

REST と SOAP

ここでは SOAP といったときに単純に SOAP エンベロープ形式を指すわけではありません。 SOAP というのはその周囲の WS-* だとか SOA だとかを含んだ一連のコンセプトを指すと考えます。

SOAP 的な考え方と REST 的な考え方(というか REST は考え方そのもの)の一番の大きな違いは、 プロトコル独立を重視するかどうかです。 SOAP 的考え方はプロトコル独立を重視します。 たとえば SOAP メッセージは HTTP でも SMTP でも UDP でも直接 TCP でも送れるように設計されています。 一方で REST には HTTP しかありません。 この両者の差は何なのでしょうか。

この差はインターフェースがどこに含まれるかの違いです。 REST では uniform interface 制約ということで HTTP が統一のインターフェースとなります。 HTTP の上をデータ(XML)が流れます。 一方で SOAP ではトランスポート独立ということで TCP, UDP, SMTP, そして HTTP の上に getX, startY などのインターフェース付きのデータ(SOAP メッセージ)が流れます。

REST と SOAP 的考え方の違い、少しだけですが雰囲気はつかめたでしょうか。 このテの話題は純粋に技術的ではなく、他の要素が絡むので語りにくいのですが、 技術者の皆さんに言いたいのは REST でも SOAP でも、 せめて技術的にはニュートラルに評価しましょう、ということです。 今日のこのポストもかなり端折って書いているので、 このまま鵜呑みにするんじゃなくて自分で調べてくださいね。

この REST 入門シリーズも次回はとうとう最終回です。

ラベル: , ,

2005-05-25

Alpine

前のエントリの続き。

同論文では Alpine の設計目標が提示されている。

  1. Stay in the XML space as much as possible.
  2. Take advantage of as much leading edge infrastructure as we can.
  3. Adopt the the handler chain pattern of Axis/JAX-RPC.
  4. Target SOAP 1.2 (POST only, WS-I Basic Profile 1.1)
  5. Document/literal mssages only, not RPC/encoded.
  6. Support XSD and Relax NG schemas.
  7. Run server-side, client-side, and as an intermediary.
  8. No support for JAX-RPC or JAX-M/SAAJ APIs.
  9. Configurable procedurally, through the Java Manage- ment API (JMX).
  10. Permit dynamic handler chain configuration during mes- sage processing.
  11. One supported parser.
  12. Run on Java 1.5 and later.
  13. No provision of side features such as a built in HTTP server, or a declarative configuration mechanism. These are delegated to other products.

この中でも注目は 1 と 3 だ。

XML の API として、彼らは XOM を念頭においているようだ。 ハンドラチェーンを使うのは「知っている XML だけを処理する」モジュールを接続して処理をするためだろう。

いやーしかし、こういう論文が Sun でも IBM でも BEA でもなく HP から出てくるところが、面白いなー。

ラベル: ,

Java SOAP スタックの再考

とても興味深い論文を読んだ。 Steve Loughran と Edmund Smith の "Rethinking the Java SOAP Stack" だ。 この論文は現在の Java の SOAP 実装スタック、特に JAX-RPC の問題点を XML セントリックな視点から明確に指摘している。 また、最後の部分で Alpine という新しい SOAP スタックのコンセプトを提案している。

Alpine の方はまだどんなものかわからないので、これからに期待したいが、 JAX-RPC の問題点の方はとても面白い。 雰囲気を伝えるために論文の第二章 "基本的な JAX-RPC の欠陥(The Fundamental Flaws of JAX-RPC)" の見出しを日本語で引用する。

  1. オブジェクト/XML のインピーダンスミスマッチ
    1. XML 要素の Java クラスへのバインディング
    2. XML の名前(Names)の Java 識別子へのマッピング
    3. Enumeration
    4. ポータブルでない型
    5. オブジェクトのグラフの直列化
    6. XML メタデータと名前空間
    7. メッセージ妥当性検証
    8. XML と直列化データの不適切な混和
    9. フォールト処理
  2. SOAP は RPC ではない
  3. SOAP は RMI ではない
  4. WSDL: 別の複雑さ

このように論文で指摘されている問題点はいくつもあるのだが、基本的には SOAP/XML Web サービスを Java 世代のプログラミング言語(Java に加えて C#, VB.NET も)にネイティブにマッピングしてしまうことへの批判となっている。 その中でも特に大きいのが XML と オブジェクトのデータモデルの違いに起因するインピーダンスミスマッチだ。 ここで指摘されている各事項は、XML をオブジェクトにマッピングしたり、 オブジェクトを XML にマッピングしたりすることが本質的に難しいことを示している。

上でも述べたとおり、この論文は XML セントリックな視点から記述されているので、 逆に RPC/RMI/Object セントリックな視点から見るとまったく許容できない内容なのかもしれない。 そういう意味で面白い文(Don Box も引用している)がある。

我々は Web サービス開発者にはただ二つの分類があると考える。 XML に満足していてそれを扱う仕事をしたいと願っている人々と、満足していないのに結局はなんだかんだいってそれを扱う人々だ。

(We believe that only two categories of web service developer exist: those who are comfortable with XML and want to work with it, and those who aren’t but end up doing so anyway.)

明らかに僕は前者だ :-)

ラベル: , ,

2005-05-24

Blog Hackers Conference 2005

Blog Hacker じゃないけど、金曜日 Blog Hackers Conference 2005 を聞きに行きます。たまにはこういうところも行かんと。 REST/Web サービスな人と時間があれば交流したいもんです。 メールか mixi で連絡ください。って誰あてだ ;-)

2005-05-23

疎結合と XML

疎結合(loosely-coupled)って何でしょう?

僕自身、適当に疎結合という言葉を使ってしまいがちですが、 ちゃんとした説明なり定義なりが必用だと感じています(自分のために)。 いいかげんな定義で話をはじめると、 各人の方向性がずれまくって議論ができないですよね。 Web サービスしかり、 SOA しかり、REST しかり。 ということで今回は僕なりに疎結合ってこんなもの、 というのを考えてみます。

ものすごく一般化してしまうと、 疎結合というのは複数のコンポーネント間の結び付きが ゆるいことを指すんでしょうね。 たぶん、ここまでは誰でも同意してくれるはず。 ただこれだけでは議論ができなくて、 このコンポーネントに何をもってくるかを決めて、 はじめて具体的な話ができます。

僕がここで話したいのは Web サービスの文脈での「疎結合」ですから、 コンポーネントは Web サービスになります。 コンポーネントがオブジェクトだとかもっと細かいレベルの話もあると思いますけど、 ここではしません。

あ、Web サービスという言葉も危いですね。 ここでは Web 上で機械(プログラム)可読なフォーマットで情報を提供するもの、 だとします(実際、僕の Web サース感はこれに近い)。 SOAP インターフェースの株価サービスかもしれないし、 AtomAPI のはてなブックマークかもしれない。 RSS フィードも含みます。

ところで、この「疎結合」をもろに扱った本があります。 タイトルがずばり「疎結合」です。 SOAP よりの Web サービスの文脈での疎結合を扱っている本です。 この本は10章で疎結合とは何かを解説しているんですが、 そこにはこんなことが書いてあります。

(前略) 多くの人々が「疎結合」という言葉を口にしますが、 その意味を正確に説明できる人はほとんどいません。 これは、疎結合が方法論もしくは作法であり、 確立された規則や仕様ではないからです。

疎結合は、俊敏性(アジリティ)、すなわち変化に適応する能力を重要視する 分散アプリケーション設計へのアプローチの一種です。 (後略)

つまり疎結合というのは分散アプリケーションの作り方、 設計の仕方に関する考え方のひとつであり、 特に決った規則や仕様はないってことです。 これは逆の意味でしっくりきました(僕には)。 これだけ曖昧な定義なら、議論の方向性が定まらないのも仕方ないですね。

僕が今考える疎結合システムのイメージはこんな感じです。

まず、サービス(コンポーネント)間のインターフェースは統一し、 半永久的に変更しません。 サービスのインターフェースに少しでも修正が入ると、 旧インターフェースを利用していたクライアントを修正しなければならないからです。

インターフェースを統一して不変にしたときに、 ではいったいどこでサービス同士の機能を差別化するのか。 それはサービス間でやり取りするデータで行います。 データ形式を思いっきり自由に拡張可能にして、 どんな種類のデータでも統一インターフェースで受け渡し可能にします。 オブジェクトだとこの拡張性が厳しいのですが、 XML と名前空間の組み合わせならぜんぜん問題ありません(ちょっと言い過ぎか)。

XML が拡張可能ということは、自分が知らない要素や属性が出てくる可能性があるということです。 でも、そんな拡張された未知のデータでもエラーにせずに、使えなければなりません。 そのために、知らない要素は無視する、という動作をデフォルトで行わなければならないのです。 SOAP の mustUnderstand 属性がデフォルトで false なのは、こういう理由からではないかと思います、たぶん。

で、このデフォルトで無視という動作は、 吉松さんがこのポストで言っている 「無邪気なまでにデータの読み手に解釈をゆだねる姿勢」 のデータの読み手側の一番簡単な実践なんだと思うのです。 本当はさらに吉松さんのポストのコメントで萩原正義さん(らしき人)が言っている「semantics を重視した…」 というのも直感的にわかりそうなのだけれど、今の僕には残念ながら理解しきれません。 だからとりあえず、 XPath なりで知ってる要素と属性をパターンマッチして知らないやつは無視、からやってみるしかないんだな、 というなんだか当たり前の結論になっちゃったなあ。

ラベル: , , , ,

2005-05-22

REST 入門(補足2) POST と PUT

» REST 入門 目次

kwatch さんから以下のようなコメントをもらいました。

POSTとPUTの説明が逆では?たしかPUTが新規作成であり、POSTは送ったリソースの処理を指定したURIに任せるということだったと思いますが。

コメント欄では返答が書ききれなかったので、補足として新しいポストを追加します。

RFC2616 では PUT の動作が二つ規定されています。

指定した URI がすでに存在している場合
PUT はその URI のリソースを修正(更新)する
指定した URI が存在しない場合
PUT はその URI のリソースを新規作成する

PUT を規定している 9.6 節には POST と PUT の違いとして以下の記述があります。

The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI, it MUST send a 301 (Moved Permanently) response; the user agent MAY then make its own decision regarding whether or not to redirect the request.

つまり PUT でも POST でもリソースを新規作成することができるのですが、以下の違いがあるということです。

PUT でリソースを新規作成する場合
クライアントが指定した URI のリソースが新規作成される
POST でリソースを新規作成する場合
クライアントが指定する URI はリソースを新規作成するリソースの URI。新規作成されたリソースの URI はサーバが決定する

ここまでは HTTP 1.1 の規定の話です。 論点は、リソースの URI を PUT でクライアントが作るのか POST でサーバが作るのか、ということです。 REST では URI はクライアントにとって不透明(opaque)であるべき、という原則があります。 そのココロはクライアントとサーバの結びつきをなるべく減らす、というものです。 PUT でリソースを新規作成する場合、クライアントはそのサーバが提供する URI 空間の管理方法を別途知らなければなりません。 このような密結合は REST あるいは Web サービスの世界では厳禁事項の一つです。

たとえば現状の Atom Publishing API では、 新しいリソースの作成はコレクション URI に POST することになっています

REST 入門の一連のポストこのような理由から、リソースの新規作成は POST で行う、と説明しています。

ラベル: ,

2005-05-21

まっとうなソフトウェア工学に期待すること

naoya さんのダイアリーに端を発してちょっとだけ議論が起きている。

まず naoya さんのオリジナルのポスト。 はてなが従来のいわゆる世間一般の開発手法を採用せず Perl でアジャイルな開発手法をを選ぶ理由として、 その開発するソフトウェアサービスの性質と 動的型付け言語の開発効率を挙げている。

対してオリオナエさんは naoya さんがソフトウェア工学を軽視している(ように見える)点を、 薬学と建築工学の例を使って批判している。

吉松さんははてなのサービスとオリオナエさんの薬の例のギャップを指摘して、 いわゆるソフトウェア工学的手法に疑問を投げかけておられる。

Don'tStopMusic さんもオリオナエさんの例とはてなの違いから いわゆるソフトウェア工学(と Java)ははてなには合わないという主張だ。

ここまで読んで思ったのは、みなさんの「ソフトウェア工学」感のずれだ。 それぞれソフトウェア工学に期待することが微妙にずれているので、 どうしても話がかみ合わないように見受けられる。

そんなときに思い出すのは檜山さんのこの文書だ。

檜山さんの記事を読むまでは僕もいわゆるソフトウェア工学に胡散臭さを感じていた。 だからといって職人芸的なアプローチについても、なんだか割り切れないものを感じていたのも事実だ。 僕はもともとは情報系の人間ではなく、学部ではロボットで遊んでいた人間なので、 ロボットの基本である機械工学といわゆるソフトウェア工学の差があまりに激しいのでびっくりしていた。 そんなところで檜山さんの言葉「どうでもいいソフトウェア工学」と「まっとうなソフトウェア工学」を得て、 やっとすっきりした。

たとえば REST アーキテクチャスタイルはまっとうなソフトウェア工学の貴重な研究成果だと思う。 もちろん REST を適用すれば何でも解決するわけではない。 でも REST スタイルを学んで設計開発するのと、何も知らずにどうでもいいソフトウェア工学で設計開発するのでは、 その結果の Web アプリケーションの品質や性能に大きな差が出るだろう。

それからはてなの成果、はてなフレームワークは Web アプリケーションフレームワークの実践としてとても素晴らしいものではないかと予想しているのだけれど、 それが優秀なハッカーの職人芸的な成果としてしか扱われないのであればとてもさみしいことだと僕は思う。 はてなフレームワークがオープンソースになったあかつきには、 アカデミックな研究者の方にぜひ、 その成功の秘訣をソフトウェア工学観点から解析してもらって、 それ以外のフレームワークに広く展開できるような研究成果をだしてもらえないものだろうか、と期待している。

ラベル:

2005-05-14

今週は濃かった

今週は濃い1週間だった。 火曜日に檜山さん川俣さんと食事。 金曜日は WWW2005天笠さんとお茶。 その後パネルを聴講して、会場で村田さん吉松さん平野さんにお会いした。 その後は幕張勤務の Shu 君と久々に会った。 脳みその心地よい疲れ。

Web Services Considered Harmful?

WWW2005 のパネルディスカッション "Web Services Considered Harmful?" に行ってきた。 いやー楽しかったなー。 パネリストは

という超豪華メンバー。以下、簡単にメモです。しょうもないメモですみません。 他のブログでまとめているのを見つけたら、更新しておきます。

  • まず Rohit Khare から背景の説明
  • SOAP, WSDL から 5年
  • WS-* 問題
  • 表面的には標準化の問題
  • 実際は技術の問題
  • 吉松さん
  • Amazon Web サービスの紹介
  • なぜ Amazon が Web サービスをやるか→ニーズがあったから
  • SOAP: 20%, XML over HTTP: 80%
  • Amazon Web サービスを使ったアプリの紹介
  • Why they are builgding?
  • because it's live!
  • Mark Baker
  • Web より祖結合なシステムはあるのか
  • やろうとしていることはアプリケーション間でのドキュメント交換
  • それを以下に単純に、疎結合で、ドキュメント指向でやるか
  • 二つの方法
  • 1 SOA
  • それぞれのアプリにそれぞれのインターフェース
  • →インターフェースを共有できない
  • 2 SQL/MOM/EDI-inspired
  • 同じインターフェースなら共有できる
  • その同じインターフェースが HTTP
  • これが Web (そして REST)のすべて
  • Adam Bosworth
  • タイトル: A Web of Data
  • Web 成功のつぼ
  • →simple, sloppy, standards, scalable
  • MySQL Users Conference 2005 と大体同じような話
  • networks are faster than disk とか
  • 9年前のビジョンが実現されていない
  • XQuery のように遅かったり
  • XSD みたいに動かなかったり
  • 末端ユーザが使えないくらい難しかったり
  • この人の話は面白すぎてメモとりきれなかった
  • ひとつだけ書けば、REST にも WS-* にも足りないものとして非同期性が挙げられていた

この後の自由討議は Mark が書いているとおり Tim と Adam の二人舞台だった。 特に Adam Bosworth がクールでスマート。 いってることは過激というか強烈というか痛烈というか、まあ彼のブログのとおりなのだけど、 本当に賢くて理に適っている。

そういえば聴衆からの質問者で一人 Web サービスよりの人がいたんだけど、 Mark の blog によればあれは Hugo Hass だったみたい。

100人くらい入る会場はほぼ埋まっていた。半分以上は外国人だったと思う。 終了後村田さんから聞いたのは、 REST のための XML 開発者の日をやりたい(やりたかった)が事務局がないのでできない、 というような話。 僕も日本でももう少し REST がメジャーになった方がいいと思っているので、 なんとかできないかなーと最近考えてます。

[update: 2005-05-14-01] 吉松さんの感想

[update: 2005-05-14-02] 会場の写真(吉松さんの Flickr 撮影者は平野さんみたい)

[update: 2005-05-14-03] 村田さんの記事 Adam Bosworth のこの採点表はメモしきれなかったところなのでうれしい!

[update: 2005-05-15] 吉松さんのまとめ

>[update: 2005-05-16]平野さんのまとめ

2005-05-12

REST 入門(その8) REST でないもの

» REST 入門 目次

WWW は REST アーキテクチャスタイルのアーキテクチャを採用した実装のひとつですが、 REST アーキテクチャスタイルでないアーキテクチャの WWW アプリケーションもかなり存在します。 REST でないものを一言で言ってしまうと、 URI と HTTP を正しく使っていないもの、ということになります。 以下では URI と HTTP の誤った使い方について説明します。

URI をクライアントで組み立てる

URI をクライアント側でごちょごちょ組み立てなければならないのなら、それは REST ではありません。 たとえば、はてなブックマーク AtomAPI が、こんなインターフェースだったらどうでしょう?

ブックマークをキーワードで検索する。

POST /uso/bookmarkSearchService HTTP/1.1
Host: b.hatena.ne.jp
Content-Type: application/xml

<keyword>REST</keyword>

レスポンスはブックマーク ID のリストになる。

HTTP/1.1 200 OK
Content-Type: application/xml

<resultList>
  <result id="332"/>
  <result id="55"/>
  <result id="9842"/>
  <result id="102944"/>
</resultList>

クライアントは /resultList/result/@id を見て、ブックマークの ID を知る。 そのブックマークを GET するには、ブックマーク取得サービスに ID をパラメータで渡す。

GET /uso/getBookmark?id=332 HTTP/1.1
Host: b.hatena.ne.jp

なんか、変ですよね。 REST であれば、ここは当然ハイパーリンクで実現すべきです。

GET の濫用、または URI へのアクションの挿入

この問題は前節の問題とビミョーに絡んでいます。 例を見てみましょう。 ブックマークを削除するときに以下のような操作をするとします。 オペレーションが削除であることは action パラメータで指定して、 削除するブックマークは id パラメータで指定します。

GET /uso/bookmarkService?action=delete&id=332 HTTP/1.1

この方式がまずい点は二つあります。 ひとつは前節で述べたとおり URI をクライアントが組み立てなければならない点。 もうひとつはオペレーションを action というパラメータで URI に組み込んでいる点です。

action パラメータを URI に埋め込むのが駄目なのには理由が二つあります。 第一に HTTP メソッドのセマンティクスを正しく利用していない点。 HTTP にはきちんと DELETE メソッドがあります。 しかし、上の例では DELETE を使わずに、GET を使っています。 これは明らかに誤用です。

この例が駄目な二つ目の理由は GET でリソース副作用(side effect)がある操作をしている点です。 GET の重要な性質としてリソースに副作用を与えないということがありました。 しかし、この URI を GET をすると、URI が指定するリソースが削除されてしまいます。 これはセキュリティ上重大な欠陥となる可能性が強い HTTP の誤用です。 少し前に話題だった CSRF の一番典型的なパターンは、この GET の濫用でしょう。

POST の濫用

すでにその5で POST の濫用については説明しましたので、ここでは簡単に振り返っておきます。 POST は四つの HTTP メソッドの中で一番柔軟なメソッドです。 しかし、HTTP メソッド本来の意味を考えて POST メソッドを利用するのが正しいのは言うまでもありません。 POST を使うときの経験則として、POST をリソースの新規作成にだけ使う、ことをいつも念頭におきましょう。

HTTP 状態コードの誤用

HTTP の状態コード(ステータスコード)は大切です。 200 とか 404 とか 500 とか 302 あたりが有名ですね。 これらの番号を誤用すると、RESTful になりません。

たとえば、エラーが起きたときのことを考えましょう。 クライアントのリクエストが悪いのに 500 を返す。 あるいは逆にサーバが悪いのに 40X を返す。 どちらも間違いです。

また、結果は明らかにエラーなのに、エラーメッセージを表示するために 200 を返すのも間違いです。 あるいは、200 を返しながら、拡張 HTTP ヘッダで詳細コードを返す。 どちらも RESTful でありません。

クッキーとセッション

REST アーキテクチャスタイルの重要な制約のひとつにステートレスがあります。 ここでいうステートレスとは、 クライアントとサーバの間の接続が状態を持っていないことを意味します。 もう少し簡単にいうと、 クライアントからサーバに送られるリクエストメッセージには、 サーバがそのメッセージを処理するのに必要な情報がすべて含まれている、ということです。 このようにアーキテクチャの制約としてステートレスを加えると、 サーバ実装の簡略化とスケーラビリティの確保につながります。

しかし、現実の Web 実装ではそうでないものも多々ありますね。 HTTP をステートフルにする代表格はクッキーを使ったセッション管理です。 REST アーキテクチャスタイルの視点からみると、 クッキーを使ったセッション管理は間違った HTTP の拡張、ということになります。

HTTP と URI を使うだけでは十分でない

今回の話題をまとめると、「HTTP と URI を使うだけでは十分でない」ということに尽きますね。 いかに HTTP と URI を使って XML をやり取りしていても、 間違った使い方であれば、それは REST アーキテクチャスタイルに従った実装ではありません。

次回は REST と SOAP の関係を、ほんの少しだけ説明しようと思います。

P.S. この weblog のタイトルを変更しました。

2005-05-09

WWW2005

今週金曜日、これを聞きに幕張まで行きます。どなたかこの日記を読んでいて、当日幕張に行きなおかつ REST architectural style に興味があって僕と情報交換してくれる日本語の通じる方は yoheiy at gmail dot com までご連絡ください :-)

2005-05-07

ソーシャルブックマーク雑感

REST 入門はちょっとお休みして、weblog っぽく日々の雑感でも。

僕は現在 del.icio.usはてなブックマークを使ってます。 この二つ、いちおう使い分けています。

del.icio.us
自分用。主として英語ページのうち、わりと目に留まって読もうと思ったものをクリップ。 その後読んだ後に感想を追加。後から検索する
はてなブックマーク
del.itio.us にポストしたもののうち、コメントがついたものをコピー。 主として自分と同じ興味の人を探すため。今のところ見つけたのはたとえば hiromark さんとか

naoya さんのこのポストを読んで思ったのは、 そういやカテゴリとかキーワードとかぜんぜん使ってないなーということ。 僕もまさに **users しか使っていなかった。 改めて自分のブックマークのカテゴリやキーワードを見てみると、 特に英語系は厳しいですね。

僕自身としては、del.icio.us のタグは自分のためにつけています。 あとで読み返して必要だったらタグを修正するし。 昔ブックマークしたページを探すのもよくするんですが、その場合はタグを使うことが多い。 で、うまくタグをつけないと見つからないので、苦労します。 苦労して見つけたらタグを修正して次回から見つけやすくする。 そんな風にしているので del.icio.us は自分にとっての財産となりつつあります。

はてなブックマークはあらかじめ日本語フィルタがかかっているのが大きいですね。 自分と同じ興味の人は日本人が前提で考えているし、日本語記事のブックマーク率は del.icio.us よりも高い。 注目のエントリーなんか暇つぶしにはもってこいだし。 自分の日記の反響が見られるのもうれしい。

それから思うのははてなの財産は人だなということ。 もちろん新しいサービスをどんどん作る中の人もだけど、 それを受けて新しい使い方をどんどん考えてくれるユーザも含めて、 財産(というか価値)なのでしょう。

ところで、はてなブックマークの注目のエントリーが 2ch のニュー速板のように見えるのは僕だけ?

2005-05-05

REST 入門(その7) ハイパーメディアの可能性

» REST 入門 目次

前回は REST で受け渡しされるリソース同士が、 URI を使ったハイパーリンクで相互に結び付けられることによってハイパーメディアを実現し、 その機能拡張には XML 名前空間などが利用できることを説明しました。

今回はより応用的なハイパーメディアと REST の関係を見ていきたいと思います。 例によってはてなブックマークを使って説明します。

リソースの URI はひとつではない

現状のはてなブックマークでは、 ひとつのブックマークエントリ(リソース)の URI は僕が知る限り以下の三つがあります。

ブックマーク一覧
http://b.hatena.ne.jp/yohei/20050429#187800
人間用 Edit URI
http://b.hatena.ne.jp/yohei/edit?eid=187800
Atom API 用 Edit URI
http://b.hatena.ne.jp/atom/edit/187800

このうち、一覧の URI は少し毛色が違いますが、 人間用および Atom API 用 EditURI は同じリソースを指していると考えて問題ないでしょう。 このようにひとつのリソースが URI を複数持つというのは珍しいことではありません。

ただ、現状では人間用と Atom API 用がお互いに無関係なのが少しさみしいですね。 以下のようにお互いの表現(representation)がリンクしていたらどうでしょうか。

人間用 http://b.hatena.ne.jp/yohei/edit?eid=187800

<html>
<head>
<title>はてなブックマーク - 傭兵ブックマーク</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="/yohei/style" />
<link rel="service.edit" type="application/atom+xml" 
    title="ブックマークの編集"
    href="http://b.hatena.ne.jp/atom/edit/187800" />
</head>
<body>
...
</body>
</html>
Atom API 用 http://b.hatena.ne.jp/atom/edit/187800

<entry xmlns="http://purl.org/atom/ns#">
  <title>何はなくとも XML InfoSet: アウトプットの定義</title>
  <link rel="related" type="text/html" 
      href="http://luckypines.blogspot.com/2005/04/blog-post_28.html" />
  <link rel="alternate" type="text/html" 
      href="http://b.hatena.ne.jp/yohei/20050429#187800" />
  <link rel="alternate" type="text/html" 
      href="http://b.hatena.ne.jp/yohei/edit?eid=187800" />
  <link rel="service.edit" type="application/x.atom+xml" 
      href="http://b.hatena.ne.jp/atom/edit/187800" 
      title="何はなくとも XML InfoSet: アウトプットの定義" />
  <author>
    <name>yohei</name>
  </author>
  <generator url="http://b.hatena.ne.jp/" version="0.1"
    >Hatena::Bookmark</generator>
  <issued>2005-04-29T20:00:05+09:00
  <id>tag:hatena.ne.jp,2005:bookmark-yohei-187800</id>
  <summary type="text/plain"
    >一連の議論の中で一番共感しました。脳みそへのインターフェース</summary>
</entry>

URI の可搬性

リンクするとうれしいことはいろいろあると思うのですが、 たとえば僕はこんなことを考えました。

はてなブックマークの専用クライアントがあるとします。 ブックマークの編集操作をしたり、ブックマークエントリを他の blog にポストしたり、別のソーシャルブックマークサービスにコピーしたりする機能を持っています。 ただ、そのままだと専用クライアントは通常あまり使いません。 なぜかというと Web を閲覧するのは Web ブラウザでするし、 ブックマークするのも bookmarklet でできるからです。 専用クライアントを使うのはせいぜいブックマークの大量削除などのときくらいでしょう。

しかし、たとえばこんな使い方ができたらどうでしょうか。 ブラウザと同じように、専用クライアントも URI 欄(アドレス欄)を持っているとします。 ブラウザで表示しているはてなブックマークの URI をコピーして専用クライアントに貼り付けられます。 すると、その URI で特定されるブックマークエントリに対して、 その専用クライアントで可能な操作が一覧される。 あるいはあらかじめ操作を選んでおいて、 URI を貼り付けるとはてなブックマークのエントリが del.icio.us と spurl に自動的にコピーされる。

ブックマークエントリリソースの表現が相互にリンクされていれば、 このプログラムの実装は簡単です。 専用クライアントは渡された URI を HTTP GET します。 返ってくる内容の Content-Type が text/html であれば、 /html/head/link[@rel="service.edit"]/@href を検索し(こんなの XPath で一発ですね) EditURI を GET すればプログラムで扱いやすい XML 形式のリソースの表現が取得できるからです。 あとは、得られた情報を適切に操作するだけです。

URI のコピーアンドペーストは最も原始的なリンクだといえます。 手作業でのコピペはダサいんですが、 これを自動化するのは簡単でしょう。 専用クライアントがブラウザの拡張プログラムであれば、 リンク選択時の右クリックメニューに「専用プログラムへ渡す」 という項目を追加するだけです。 この機能はハイパーリンクに他なりません。

このように、 URI だけでアプリケーション連携を実現できるのが REST(WWW) アーキテクチャスタイルの素晴らしい点です。 これはいわゆる疎結合(loosely-coupled)という性質です。

コンテントネゴシエーションによるソリューション

前節の URI コピペの実装には別の方法もあります。 HTTP のコンテントネゴシエーションを使う方法です。 これは同じ URI でも、クライアントが指定した Content-Type のリソース表現を返すというものです。

例を見てみましょう。 専用クライアントは、人間用 URI に以下のリクエストを発行します。

GET /yohei/edit?eid=187800 HTTP/1.1
Host: b.hatena.ne.jp
Accept: application/x.atom+xml; q=1.0, text/html; q=0.8, */*; q=0.1

サーバは Accept ヘッダを解析することで、 クライアントが必要としているのが HTML よりも Atom 形式であることがわかります。

このように実装してあると、 ブラウザで表示している URI と専用クライアントが操作する URI がまったく同じになります。 ただし、クライアント側の選択で、転送されるリソースの表現が HTML になったり、Atom になったりします。

XHTML によるソリューション

実はさらに別の方法も考えられるのです。 それはブックマークリソースが返す表現を XHTML にして、 head 要素の中に Atom の XML を丸ごと入れてしまう方法です。 このようにすれば、そもそも表現自体をクライアントごとに分ける必要もなく、 ただひとつの URI で済ませることができるでしょう。

まとめと課題

これまで見てきたように、URI と HTTP を組み合わせたハイパーメディアにはいろいろな可能性がありそうです。 さらに XML/XHTML を組み合われば、 ブラウザとそれ以外の専用アプリ(あるいはブラウザの拡張)が 自由に連携できそうです。

しかし、現実はそれほど甘くありません。 きちんと REST アーキテクチャスタイルの制約に従ったアーキテクチャの Web アプリケーションであれば、 あまり問題なく XML を使った RESTful な Web サービスを提供できるでしょう。 しかし世の中にはそうでない Web アプリケーション実装が多いのも事実です。

次回は REST アーキテクチャスタイルに反する Web の実装を見ていこうと思います(連休中に書ききれるかと思ったけど無理っぽいなー)。

REST 入門(その6) ハイパーリンクと XML

» REST 入門 目次

前回、はてなブックマークを例にリソースと四つの HTTP メソッド (GET, POST, PUT, DELETE) の関係について解説しました。 今回は、リソース同士をどのように関連付けるか、について解説します。

前回の記事でこんな疑問を持った人はいなかったでしょうか。

ひとつのブックマークリソースにいろいろなメソッドを適用しているけれど、 そのブックマークリソースにはいったいどうやってたどり着くのか。

たとえば PostURI に POST して新規作成したブックマークを全部覚えておけば、 それぞれのリソースの URI はわかります。 しかしそれではソーシャルブックマークサービスを使う意味がありません。 ローカルディスクまたはローカルサーバに保存しておくのではブックマークを共有することができないし、 そもそも自分以外の人のブックマークにアクセスできないのでは、 ソーシャルブックマークとは言えません。 残念ながら、現状のはてなブックマーク AtomAPI は、以下の操作しか提供されていません。

  • 新規ブックマークの投稿 (PostURI への POST)
  • 投稿したブックマークのタイトル、コメントの変更 (EditURI への PUT)
  • 投稿したブックマークの削除 (EditURI への DELETE)
  • 投稿したブックマークの参照 (EditURI への GET)
  • 最近投稿したブックマークの一覧の取得 (FeedURI への GET)

他のユーザのブックマークを閲覧することもできないし、 そもそも自分が登録したブックマークの一覧を全部取得することもできません。

はてなブックマーク AtomAPI はまだ発展途上のサービスなので、機能不足なのは仕方ありませんが、 REST とハイパーメディアの関係を語るにはちょっとさみしいのも事実です。 以下では、はてなブックマーク AtomAPI にない機能を独自に拡張しながら、 REST とハイパーメディア、それから XML の関係を解説します。

REST ではリソース同士の関係をハイパーリンクで記述します。 たとえば、自分が「最近登録したブックマークのリスト」というリソースの URI は

http://b.hatena.ne.jp/atom/feed

になります。 この URI を GET してみましょう。

GET /atom/feed HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei",...
HTTP/1.1 200 OK
Content-Type: application/x.atom+xml

<feed version="0.3" 
      xmlns="http://purl.org/atom/ns#"
      xml:lang="ja">
  <title>傭兵ブックマーク</title>
  <link rel="alternate" type="text/html" href="http://b.hatena.ne.jp/yohei/" />
  <link rel="service.post" type="application/x.atom+xml"
      href="http://b.hatena.ne.jp/atom/post" title="傭兵ブックマーク" />
  <modified>2005-04-29T21:43:51+09:00</modified>
  <author>
    <name>yohei</name>
  </author>
  <id>tag:hatena.ne.jp,2005:bookmark-yohei</id>
  <generator url="http://b.hatena.ne.jp/" version="0.1">Hatena::Bookmark</generator>
  
  <entry>
    <title>何はなくとも XML InfoSet: アウトプットの定義</title>
    <link rel="related" type="text/html"
        href="http://luckypines.blogspot.com/2005/04/blog-post_28.html" />
    <link rel="alternate" type="text/html"
        href="http://b.hatena.ne.jp/yohei/20050429#187800" />
    <link rel="service.edit" type="application/x.atom+xml"
        href="http://b.hatena.ne.jp/atom/edit/187800"
        title="何はなくとも XML InfoSet: アウトプットの定義" />
    <issued>2005-04-29T20:00:05+09:00
    <author>
      <name>yohei</name>
    </author>
    <id>tag:hatena.ne.jp,2005:bookmark-yohei-187800</id>
    <summary type="text/plain"
      >一連の議論の中で一番共感しました。脳みそへのインターフェース</summary>
  </entry>
...
</feed>

レスポンスは Atom で定義されるいわゆる Atom フィードになります。 このフィードには最近登録したブックマークが 20 件入っています。 フィードに含まれるそれぞれのエントリには link 要素によって表現される ハイパーリンクがいくつか含まれます。

もっとも重要なリンクは EditURI へのリンクです。

<link rel="service.edit" type="application/x.atom+xml"
    href="http://b.hatena.ne.jp/atom/edit/187800"
    title="何はなくとも XML InfoSet: アウトプットの定義" />

前回、いろいろと操作したブックマークリソースの URI がこの EditURI になります。

その他にもリンクがあります。 一つ目は、このブックマークのターゲット、 ブックマークした Web ページへのリンクです。

<link rel="related" type="text/html"
    href="http://luckypines.blogspot.com/2005/04/blog-post_28.html" />

もうひとつは、このブックマークリソースの HTML 表現、 つまり人間用の Web ページへのリンクです。

<link rel="alternate" type="text/html"
    href="http://b.hatena.ne.jp/yohei/20050429#187800" />

それぞれのリンクは、別のリソースの URI を指定していますので、 リソースに HTTP メソッドを適用することができます。 どの HTTP メソッドを適用できるかは仕様しだいです。 たとえば EditURI であれば、GET/PUT/DELETE が適用できることが、 明記されています。

過去のブックマークの取得

前節で解説した FeedURI は現状のはてなブックマーク AtomAPI でサポートされている機能です。 しかし、現在のフィードの実装では最新の20件しか取得することができません。 それ以前のブックマークを取得する方法を検討してみましょう。

この目的を達成するにはいくつかの方法が考えられると思いますが、 今回は検索インターフェースをつける方法をご紹介します。

ここで登場するリソースは、「検索結果」リソースです。 検索結果リソースはこれまでみてきたリソースとは少し趣が異なります。 たとえばキーワード "REST" を検索した検索結果の URI は以下のようになります。

http://b.hatena.ne.jp/atom/search?q=REST

また、キーワード "XML" を検索した検索結果の URI は以下のようになります。

http://b.hatena.ne.jp/atom/search?q=XML

サンプルで明らかだと思いますが、重要なのは URI の "?q=" の部分です。 これは問合せ文字列(query string)と呼びます。 通常 URI はクライアントで構築することはありませんが、 この問合せ文字列だけはクライアント側で操作することができます。 その結果生成された URI はそのキーワードの検索結果の URI を示します。

空文字列のキーワードも許可するように実装すれば、 これまで自分が登録したブックマークをすべて含む検索結果のリソースを特定する URI を作ることもできます。

多くの場合、検索結果は膨大な件数になります。 そのため結果を複数に分けるいわゆるページング処理が必要となります。 分割された結果一つ一つがそれぞれリソースとなります。 21番目の結果から20件を表現するリソースの URI はたとえば以下のようになります。

http://b.hatena.ne.jp/atom/search?q=REST&start=21&num=20

同様の情報を検索結果リソース自身にも入れましょう。 XML 名前空間を使えば、標準以外の情報を Atom フィードに組み込むのは簡単です。 都合のよいことに、OpenSearch RSS という規格で、この用途にぴったりのタグを規定してくれています。

GET /atom/search?q=REST&start=1&num=20 HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei",...

HTTP/1.1 200 OK
Content-Type: application/x.atom+xml

<feed version="0.3" 
      xmlns="http://purl.org/atom/ns#"
      xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
      xml:lang="ja">
  <title>傭兵ブックマーク</title>
  <link rel="alternate" type="text/html" href="http://b.hatena.ne.jp/yohei/" />
  <link rel="service.post" type="application/x.atom+xml"
      href="http://b.hatena.ne.jp/atom/post" title="傭兵ブックマーク" />
  <modified>2005-04-29T21:43:51+09:00</modified>
  <author>
    <name>yohei</name>
  </author>
  <id>tag:hatena.ne.jp,2005:bookmark-yohei</id>
  <generator url="http://b.hatena.ne.jp/" version="0.1">Hatena::Bookmark</generator>
  <openSearch:totalResults>24</openSearch:totalResults>
  <openSearch:startIndex>1</openSearch:startIndex>
  <openSearch:itemsPerPage>20</openSearch:itemsPerPage>
...
<:/feed>

あまり詳しく説明しませんが、この検索結果は24件あって、 そのうちここでは1番から20件分を表示している、ということになります。 21番から24番までの検索結果のリソースへのリンクをつけてもよいのですが、 openSearch には適当なタグがなかったのでしていません。 とりあえずクライアント側で問合せ文字列を構築することで対応できます。

なんだか長くなってしまったので、今回はここまで。 次回も続けて、今度はもっと応用的な REST におけるハイパーリンクとハイパーメディアの可能性について解説したいと思います。