yohei-y:weblog

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

2005-04-29

REST 入門(その5) 四つの動詞 -- GET, POST, PUT, DELETE

» REST 入門 目次

前回、URI で特定できるリソースに HTTP の GET という動詞を適用して、 ある時点・条件での状態の表現を転送するのが REST だという説明をしました。 URI (名詞)に適用できる動詞は GET だけではありません。

今回は GET 以外の三つの動詞を紹介します。

前提知識

ここでは実際に稼動している REST 実装の例としてはてなブックマーク AtomAPI を使います。 はてなブックマークそのものの説明はしませんので、あらかじめご了承ください。

はてなブックマークに登録したひとつのブックマークを考えてみてください。 このひとつのブックマークエントリが、対象のリソースになります。 たとえば REST 入門の目次をブックマークしたとします。 このブックマークの URI は http://b.hatena.ne.jp/atom/edit/175062 です。 まずは GET してみましょう。

GET /atom/edit/175062 HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei", ...

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

<entry xmlns="http://purl.org/atom/ns#">
  <title>傭兵日記: REST 入門</title>
  <link rel="related" type="text/html"
      href="http://yohei-y.blogspot.com/2005/04/rest_23.html" />
  <link rel="alternate" type="text/html"
      href="http://b.hatena.ne.jp/yohei/20050424#175062" />
  <link rel="service.edit" type="application/x.atom+xml"
    href="http://b.hatena.ne.jp/atom/edit/175062" title="傭兵日記: REST 入門" />
  <author>
    <name>yohei</name>
  </author>
  <generator url="http://b.hatena.ne.jp/" version="0.1"
    >Hatena::Bookmark</generator>
  <issued>2005-04-24T:14:46:00+9:00</issued>
  <id>tag:hatena.ne.jp,2005:bookmark-sample-175062</id>
  <summary type="text/plain">REST の入門</summary>
</entry>

実際にはてなブックマークから GET するには認証用の X-WSSE ヘッダが必要なことに注意してください。 また、レスポンスに含まれるのは HTML ではなく XML 形式のブックマークとなります。 XML に含まれる情報で重要なのは title 要素と summary 要素になります。 summary 要素はいわゆる「コメント」です。

以下では、このブックマークエントリ(リソース)の URI に、 GET 以外の HTTP メソッドを適用してみます。

リソースを更新 -- PUT

一度は登録したけれど、つけたコメントが気に入らないので修正したいとします。 こんなときは HTTP の PUT メソッドを使います。PUT リクエストはこのようになります。

PUT /atom/edit/175062 HTTP/1.1
Host: b.hatena.ne.jp
Content-Type: application/x.atom+xml
X-WSSE: UsernameToken Username="yohei", ...

<entry xmlns="http://purl.org/atom/ns#">
  <summary type="text/plain"
    >REST(Representational State Transfer) の入門</summary>
</entry>

PUT のレスポンスはこのようになります。

HTTP/1.1 200 OK

今、更新した URI を再度 GET することができます。

GET /atom/edit/175062 HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei", ...

取得される XML は、コメントが修正されたものになっているはずです。

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

<entry xmlns="http://purl.org/atom/ns#">
  <title>傭兵日記: REST 入門</title>
  <link rel="related" type="text/html"
      href="http://yohei-y.blogspot.com/2005/04/rest_23.html" />
  <link rel="alternate" type="text/html"
      href="http://b.hatena.ne.jp/yohei/20050424#175062" />
  <link rel="service.edit" type="application/x.atom+xml"
    href="http://b.hatena.ne.jp/atom/edit/175062" title="傭兵日記: REST 入門" />
  <author>
    <name>yohei</name>
  </author>
  <generator url="http://b.hatena.ne.jp/" version="0.1"
    >Hatena::Bookmark</generator>
  <issued>2005-04-24T:14:46:00+9:00</issued>
  <id>tag:hatena.ne.jp,2005:bookmark-sample-175062</id>
  <summary type="text/plain"
    >REST(Representational State Transfer) の入門</summary>
</entry>

リソースを削除 -- DELETE

ブックマークを削除したい場合は DELETE メソッドを使います。

DELETE /atom/edit/175062 HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei", ...

HTTP/1.1 200 OK

DELETE が成功すると、同じ URI を再度 GET することはできません。

GET /atom/edit/175062 HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei", ...

レスポンスは HTTP エラーになります。

HTTP/1.1 404 Not Found

リソースを新規作成 -- POST

先ほどのブックマーク、消してしまったけれどやっぱり元に戻したいとします。 そんなときは POST でブックマークリソースを新規に作成します。 でも、どの URI に POST したらよいのでしょうか。 リソースを新規に作成するわけですから、リソース自体がまだ存在せず、 したがって URI もありません。

こういう時はリソースを新規作成するためのリソースを用意します。 はてなブックマークではこのリソースの URI を PostURI と呼んでいます。 それでは POST してみましょう。

POST /atom/post HTTP/1.1
Host: b.hatena.ne.jp
X-WSSE: UsernameToken Username="yohei", ...

<entry xmlns="http://purl.org/atom/ns#">
  <link rel="related" type="text/html"
      href="http://yohei-y.blogspot.com/2005/04/rest_23.html" />
  <summary type="text/plain"
    >REST(Representational State Transfer) の入門</summary>
</entry>

正常に受け付けられると以下のようなレスポンスが返ってきます。

HTTP/1.1 201 OK
Content-Type: application/x.atom+xml
Location: http://b.hatena.ne.jp/atom/edit/xxxx

<entry xmlns="http://purl.org/atom/ns#">
  <title>傭兵日記: REST 入門</title>
  <link rel="related" type="text/html"
      href="http://yohei-y.blogspot.com/2005/04/rest_23.html" />
  <link rel="alternate" type="text/html"
      href="http://b.hatena.ne.jp/yohei/20050424#xxxx" />
  <link rel="service.edit" type="application/x.atom+xml"
    href="http://b.hatena.ne.jp/atom/edit/xxxx" title="傭兵日記: REST 入門" />
  <author>
    <name>yohei</name>
  </author>
  <generator url="http://b.hatena.ne.jp/" version="0.1"
    >Hatena::Bookmark</generator>
  <issued>2005-04-24T:17:46:00+9:00</issued>
  <id>tag:hatena.ne.jp,2005:bookmark-sample-xxxx</id>
  <summary type="text/plain"
    >REST(Representational State Transfer) の入門</summary>
</entry>

レスポンスには Location ヘッダがあります。 これが新規作成されたリソースの URI になります。

POST メソッドは、その自由度の高さから、濫用される傾向にあります。 実際には GET, PUT, DELETE で行えることも、POST でできてしまうのです。 しかし、HTTP メソッド本来の意味を考えて POST メソッドを利用するのが正しいのは言うまでもありません。 POST を使うときの経験則として、POST をリソースの新規作成にだけ使う、 というものがあります。新しいリソースを POST する、と覚えましょう。 Paul Prescod の "Common REST Mistakes" の2番がこれに該当します。

まとめ

今回の POST, PUT, DELETE と、前回の GET はある点で大きく異なります。 それは GET がリソースの状態に影響を与えないのに対して、 それ以外の三つの動詞がリソースの状態に何らかの影響を与える可能性がある点です。 このような性質を副作用(side effect)といいます。 副作用のない GET はキャッシュという大きな可能性を持つことになります。 キャッシュについては機会があれば説明しようと思います。

これまでの内容をまとめると以下のようになります。

  • GET はリソースを取得するメソッド
  • PUT はリソースを更新するメソッド
  • DELETE はリソースを削除するメソッド
  • POST はリソースを新規作成するメソッド
  • GET はリソースに副作用を与えない

REST では、リソースを操作するインターフェースにはこの四つのメソッドしかありません。 getXx() も setXx() も startXx() も createXx() もないのです。 これは REST アーキテクチャスタイルの持つ大きな制約のひとつ、 統一インターフェース(uniform interface)です。

次回は、Web の最大の特徴であるリンクと REST の関係について解説したいと思います。

[update 2005-05-22] POST と PUT についての記事を追加しました。

[update 2007-09-21] 2007年7月に Atom Publishing Protocol は標準化作業が終了しました。また、その技術解説を WEB+DB PRESS Vol.40 に書いています

ラベル: ,

2005-04-27

REST 入門(補足) アーキテクチャとアーキテクチャスタイル

» REST 入門 目次

僕の説明だと、どうもアーキテクチャとアーキテクチャスタイルについて混乱を招きそうなので、 補足しておきます。 デザインとデザインパターンが違うように、 アーキテクチャとアーキテクチャスタイルは別物です。 デザインパターンの本といえば GoF とか結城さんの2冊が有名ですね。 デザパタ本に載っているのはデザインそのものではなくデザインのパターンです(ムズカシイ?)。

つまりこういうことです。 僕たちは結城さんの本でデザインパターンを勉強します。 デザインパターンはある問題領域においての経験則的なクラス設計の指針、作法、流儀です。 あの本自体に自分のプログラムのデザイン(設計)が書いてあるわけではありません。 本に書いてあるパターンを学習して、そのパターンを自分自身のプログラムのデザインに適用します。 デザインというのは本に書いてあるのではなく、 僕たちが実際に作るプログラムにおいて初めて具現化されるものなのです。

アーキテクチャスタイルも同様です。 現実の世界で作られる実際のシステムはアーキテクチャを持っています。 そのアーキテクチャを設計するときに、ただ闇雲にものを作っていくのではなく、 世の中にすでにたくさんあるアーキテクチャ設計の指針、作法、流儀を適用するはずです。 そのほうが作業効率がいいし、先人の知恵を活用することできちんと動くものが作れるから。

でも、実際は忙しかったり、納期が迫っていたり、 調べるのが面倒だったり、とにかく作らなければならなかったり、 あるいは単に無知だったりして、アーキテクチャスタイルを適用しない(できない)こともあります。 すると、いちおう動くんだけどちょっと変なシステムや、 最悪だとパフォーマンスやセキュリティに重大な欠陥を抱えたシステムができたりします。

REST の実装は Web だといいましたが、 REST じゃない実装の Web もあります。 後ほど詳しく説明する予定ですが、 たとえば Cookie、たとえば URI へのアクション埋め込み、 キャッシュを無視した POST の濫用、 などはすべてアーキテクチャスタイルとしての REST を無視したか、 あるいは知らないために起きている問題です。

本題がちとずれました。 元の話(アーキテクチャとアーキテクチャスタイル)に戻ります。 アーキテクチャはあなた自身のシステムのものです。 それを作るときに、アーキテクチャスタイルを適用しましょう。

ラベル: , ,

2005-04-24

REST 入門(その4) HTTP GET -- その絶大な効果

» REST 入門 目次

前回は、リソースの特徴について解説しました。 しかし、なぜリソースが重要なのかはまだわからないと思います。 今回はその一部を紹介します。

まず、おさらいしましょう。 僕たちは以下のリソースを例に使っています。

  • 東京の天気予報
  • 2005年8月24日のスケジュール
  • 新花巻駅の写真
  • Dijkstra 著 "Go To Statement Considered Harmful"
  • 僕の最近のブックマーク

そして、それぞれのリソースの識別子(URI)は以下のようになります。

  • http://weather.yahoo.co.jp/weather/jp/13/4410.html
  • https://example.com/schedule/20050824
  • http://www.flickr.com/photos/60043209@N00/6337155/
  • http://www.acm.org/classics/oct95/
  • http://del.icio.us/yohei

ここで質問です。URI を与えられたら、あなたは何をしますか?

ここで答を直接聞けないのは残念ですが、大多数の人は、URI をコピーして Web ブラウザの URI 欄(IEだったらアドレス欄)に貼り付け、 そしてリターンキーか「移動」ボタンを押すのではないでしょうか。 上記の URI は、スケジュール以外は全部実際にブラウザで見ることができるURL ばかりです。 ぜひコピー&ペーストしてみてください。

URL 貼り付けというなにげない日常的な行為、これが REST では非常に重要なのです。 ブラウザに URI を入力してリターン、するとブラウザはURI に示された Web サーバに対して HTTP の GET メソッドを発行します。

GET /weather/jp/13/4410.html HTTP/1.1
Host: weather.yahoo.co.jp

Web サーバは結果(その時点での東京の天気予報の HTML ページ)をブラウザに返します。

HTTP/1.1 200 OK
Content-Type: text/html; charset=euc-jp

実際の HTML がここに入る

世界中の人々が日々行っているこのなにげない作業を REST 流に説明すると、 名詞(リソース)に動詞(HTTP GET)を適用した、ことになります。

ナンジャソリャ? と思った人もいるかもしれませんが、これはいわゆる「抽象化」です。 現実の世界で起きている Yahoo の東京の天気予報のページをブラウザに表示する、 という行為から個別の事情を取り払い、 なるべく汎用的に使える言葉で説明する(抽象化する)と 「Yahooの東京の天気予報」というリソースを取得(ゲット、GET、HTTP で GET)する(取得する」という動詞を適用)、 となるのです。

この HTTP GET という抽象化は絶大な効力を発揮しています。 あるリソースを識別する URI さえ与えられれば、 ブラウザを使って HTTP GET を適用するだけで、 そのリソースのある時点での表現を取得できるのです。 それが HTML 文書だろうと、PNG 画像だろうと、.swf ファイルだろうと、Javascript だろうと関係ありません。

ここで「リソースのある時点での表現」という言葉が出てきました。 これは REST の名前の元になっている Representational state のことです。 Representational state とは、あるリソースのある時点・条件での状態の表現を指します。 今日の時点での天気予報リソースと明日の時点での天気予報リソースは、 リソース自体の状態が異なるので取得できる表現も違います。 また、その表現は HTML かもしれないし、XML かもしれないし、PDF かもしれないし、はたまた何か別の形式かもしれません。 この表現をネットワークを介して転送する(Transfer)のが Representational State Transfer (REST) です。

今回はここで終了です。 次回は GET 以外の動詞を見ていこうと思います。

ラベル: ,

2005-04-23

REST 入門(その3) 全てはリソースから

» REST 入門 目次

では(やっと) REST の具体例を見ていきましょう。

REST で最も重要な概念はリソースです。以下にリソースの具体例を挙げてみます。

  • 東京の天気予報
  • 2005年8月24日のスケジュール
  • 新花巻駅の写真
  • Dijkstra 著 "Go To Statement Considered Harmful"
  • 僕の最近のブックマーク

REST においてリソースとは名前のつくあらゆる情報を指します(つまり名詞ですね)。 たとえば、「東京の天気予報」というリソースには今日の天気予報も明日の天気予報も含まれるでしょう。 あるいは「2005年8月24日のスケジュール」には僕のスケジュールだけでなく、 あなたのスケジュールも含まれるかもしれません。 リソースで重要なのは、その意味です。 リソースの実体は時間や条件によって変化するかもしれませんが、 その意味は不変です(これが名詞たる所以)。

上記のリソースの例を再度見てください。 これらは WWW (= REST の実装) 上に存在するものばかりです。

  • 「東京の天気予報」は Yahoo Japan の東京地方の天気予報のページ
  • 「2005年8月24日のスケジュール」は会社のグループウェアのスケジュール
  • 「新花巻駅の写真」は Flickr に登録した東北旅行のときの一枚の写真
  • 「Dijkstra 著 "Go To Statement Considered Harmful"」はこのページ
  • 「僕の最近のブックマーク」はソーシャルブックマークサイト del.icio.us のページ

といったぐあいです。

全てのリソースは識別子を持ちます。 Web の識別子といえば、URI (Uniform Resource Identifier) ですね。 もう一度サンプルを見てください。

それぞれの URI は以下のようになります。

  • http://weather.yahoo.co.jp/weather/jp/13/4410.html
  • https://example.com/schedule/20050824
  • http://www.flickr.com/photos/60043209@N00/6337155/
  • http://www.acm.org/classics/oct95/
  • http://del.icio.us/yohei

ここで、リソースの特徴を考察してみます。 上記の例のとおり、リソースは URI で識別される情報です。 URI で識別される情報は、時間や条件によって内容が変化する可能性があります。 たとえば、今日見る天気予報と明日見る天気予報では、含まれる内容は異ります。 しかし、両者とも東京の天気予報であることにはかわりありません。 今、リソースの内容と書きましたが、その内容は取得する時点でのリソースの状態(state)で決まります。 天気予報というリソースは、時間の経過と共に状態が変化していくと考えるとわかりやすいと思います。 もちろん状態が変化しないリソースもあります。 ダイクストラのレターの状態が変化する可能性はもうないですよね。

ここまでで、REST におけるリソースの特徴をまとめると以下のようになります。

  • 全ての情報はリソース
  • リソースは識別子(URI)を持つ
  • リソースの状態は時間や条件とともに変化する可能性がある
  • リソースの意味は時間や条件が変化しても不変である

このリソースが、REST では非常に重要になります。 その秘密は、次回以降で説明します。

ラベル: ,

REST 入門(その2) アーキテクチャスタイルとは?

» REST 入門 目次

REST そのものを説明する前に、まずアーキテクチャスタイルとは何なのかを解説します。

アーキテクチャスタイル(英文では architectural style です) は別名(マクロ)アーキテクチャパターンともいい、 複数のアーキテクチャに共通する性質、様式、作法あるいは流儀を指す言葉です。 パターンという言葉からデザインパターンを想像する人も多いかもしれませんが、 いわゆるデザインパターンは別名マイクロアーキテクチャパターンといい、 アーキテクチャスタイルよりも粒度の細かいクラスなどの設計様式を指します。

具体例を挙げましょう。
たとえば MVC (Model View Controler) はアーキテクチャスタイルの一種です。 他にパイプ&フィルタ、インタプリタ、イベントシステムなどもアーキテクチャスタイルになります。

REST は数あるアーキテクチャスタイルの中でも特にネットワークシステムのアーキテクチャスタイルになります。 ネットワークシステムのアーキテクチャスタイルとして最も有名なのはみなさんご存知のクライアントサーバです。 サーバとクライアントが線で結び付いている絵を思い浮べてください。

クライアントサーバと聞いて「あれれ」と思った人がいるかもしれませんね。 「はじめに」で REST は Web のアーキテクチャスタイルだと言いました。 しかし、Web はクライアントサーバでもあります。 これはいったいどういうことでしょうか。

実は REST はクライアントサーバから派生したアーキテクチャスタイルなのです。 素のクライアントサーバアーキテクチャスタイルにいくつかの制約を加えていくと、 REST アーキテクチャスタイルになります。 この「制約」というのはアーキテクチャスタイルにおいて重要な概念です。 一般にソフトウェアアーキテクチャは複数のコンポーネントを組み合わせて実現しますが、 それぞれのコンポーネントがバラバラに動いているのでは動作しません。 そこで、各コンポーネントに制約を課していきます。 その結果、全体として各コンポーネントが協調して動作するようになります。

クライアントサーバから REST に至る過程で加えられた制約には、 たとばステートレスやキャッシュなどがあります。

最後に、アーキテクチャスタイルとは特定の実装を指すものではないことに注意してください。 WWW は REST の一実装形態です。WWW 以外の REST の実装も考えられます。 しかし、現実には REST といえば WWW のアーキテクチャスタイルを指す場合が多いので、 これからは特にことわりなく REST の実装例として WWW を使っていきます。

はやっと REST そのものについて記述します(長いなー)。

[update 2005-04-27 アーキテクチャとアーキテクチャスタイルについて補足を追加しました。]

ラベル: ,

REST 入門(その1) はじめに

» REST 入門 目次

REST は Apache 創始者のひとりであるロイ・フィールディングさんが、 彼の博士論文で提唱したネットワーク分散システム、特に WWW のアーキテクチャスタイルです。 WWW 技術はなぜ成功したのか、その特徴は何なのか、 ということについてソフトウェアアーキテクチャの観点から見直し、 そのあるべき姿について論じるための基礎的な資料となるものです。

REST は既存の Web アプリケーション(人間が使うサービス)だけではなく、 いわゆる Web サービス(機械が使えるサービス)のためのアーキテクチャスタイルでもあります。 いわゆる SOAP を使った Web サービスとはアーキテクチャが真っ向から対立するため、 REST と SOAP はしばしば対立軸で語られます。

残念なことに、日本ではアーキテクチャスタイルとしての REST はあまり論じられてこなかったように筆者は感じています(間違いだったらゴメンナサイ)。 そのため単なる XML ベースの API としての REST のみが注目されているのが現状です。

しかしながら Web アプリケーションや Web サービスを構築するときに、 アーキテクチャスタイルとしての REST に関する知識があるとスケーラビリティやユーザビリティが向上するはずです。 もしあなたが CORBA や DCOM を知っているなら、REST とのアーキテクチャの違いが興味深いかもしれません。 もしあなたが XML guy なら :-) REST は XML の王道だと感じるかもしれません。

これからの一連のポストは、ある程度の専門知識を前提として記述します。 ソフトウェア工学やネットワークに関する基礎知識があることが望ましいです。 また、サンプルを理解するために HTTP, URI, XML の基礎知識が必用です。

次の記事では、まずアーキテクチャスタイルとは何なのかを解説します。

ラベル: ,

REST 入門

日本語の REST のリソース集を以前作ったのだが、 日本語では一般人向けの解説がない。 sheepman 氏の REST のページはすばらしいんだけど、多少わかっている人向けだ。 市山氏のプレゼン資料は RoyF の論文を詳しく解説していてよいのだけれど、いかんせんアカデミックすぎる。 技術的な要素も抑えつつ、入門者にもわかりやすい解説はないものかと探していたのだが、みつからない。 英語の文書を訳すことも考えたんだけど、あまりよいものが見つからない。
で、結局自分で書くことにした。
最初はひとつのポストで済ませるつもりだったんだけど、書き始めたら長くなってしまったので、複数のポストに分けることにした。 えらそうなことを書いたが、内容は「ないよりマシ」といったレベルだろう。
前書きが長くなったけど(ここから始まりです。ですます調なのは入門記事だから)、 この記事(から始まる一連のポスト)は Representational State Transfer (REST) の日本語での紹介です。 僕(yohei)自身、REST を完全に理解しているわけではありませんので、 間違いやコメントなどを yoheiy at gmail dot com まで頂ければと思います。 もちろん、この日記のコメントでご指摘頂いても構いません。
このポストは目次用です。新しい記事がポストされたら随時変更します。 一連の記事のインデックスページとしてご利用ください。
  1. はじめに
  2. アーキテクチャスタイルとは
  3. 全てはリソースから
  4. HTTP GET -- その絶大な効果(IE で画面が真っ白になる場合はメニューの表示→エンコード→Unicode(UTF-8) を選んでください)
  5. 四つの動詞 -- GET, POST, PUT, DELETE
  6. ハイパーリンクと XML
  7. ハイパーメディアの可能性
  8. REST でないもの
  9. REST と SOAP
  10. 終わりに
ではまず「はじめに」から
以下は追記です(2007-09-21)。 その後、Web 上でいろいろと REST に関する記事を書いたり、雑誌に連載をしたりしています。
さらに追記(2010-04-08) このエントリを拡張してさらに詳しくRESTについて書いた本を書きました。こちらもぜひご参照ください。

ラベル:

2005-04-19

Google Fight : Make this fight with googleFight rest VS soap

Google Fight というサイトがある。

使ってみればわかるが、要は二つのキーワードの Google での検索件数を戦わせるというジョークサイトだ。で、真っ先に思いついたのが REST vs SOAP。やってみたら REST の圧勝だった。

で、この Google Fight は RESTful に作ってあって、それぞれの対戦がブックマーク可能である。

そこで REST vs SOAP を del.icio.us に登録してみた。

登録したときの下心は http://del.icio.us/tag/rest を bloglines でチェックしている某Restafarianがこれを見つけてくれるのではないかということ。

そしたら見事に引っかかって :) ブックマークしてくれた

ちょっと嬉しい。

ラベル: ,

Object-Oriented Languages Considered Harmful

スラドで見たので、自分の名前でやってみたら、なんだかとっても意味深なタイトルの論文が出来上がってしまった。中身はぜんぜん違うんだけど

2005-04-13

del.icio.us ボタンも付けてみた

はてなブックマークボタンを付けたのだが、僕が常用している SBS は del.icio.us なので、そっちのボタンも付けようとしたものの、ブックマークに追加する方はうまい方法を見つけられなかった。del.icio.us api だとうまくいかないし、bookmarklet はユーザ名が入ってしまっている。仕方がないので、「このエントリーを含むブックマーク」の方だけ実装した。ミソは javascript の MD5 ライブラリ。del.icio.us の各ブックマークリソースの URL はオリジナル URL の MD5 ハッシュを含んでいるので、下記のような javascript で実現できる。

<script type="text/javascript">
  var hash = hex_md5("<$BlogItemPermalinkUrl$>");
  var url = "http://del.icio.us/url/" + hash;
  document.write("<a href='" + url +
    "'><img src='http://del.icio.us/img/delicious.gif' height='18' width='18'"
    + " alt='このエントリーを含む del.icio.us ブックマーク'"
    + " title='このエントリーを含む del.icio.us ブックマーク'"
    + " style='border: none\; display: inline\; margin-left: 5px\;'></a>");
</script>

これ作るのに大体30分くらいだった。

Blogger ではてなブックマーク用ボタンを追加する

僕の日記の記事にそれぞれはてなブックマーク用ボタンを付けるようにしてみた。Blogger のテンプレートで下記を適当なところに入れるだけです。

<a href="http://b.hatena.ne.jp/entry/<$BlogItemPermalinkUrl$>"><img
 src="http://d.hatena.ne.jp/images/b_entry.gif" width="16" height="12"
 style="border: none; display: inline; margin-left: 20px;"
 alt="このエントリーを含むはてなブックマーク"
 title="このエントリーを含むはてなブックマーク" /></a>
<a href="http://b.hatena.ne.jp/append?<$BlogItemPermalinkUrl$>"><img
 src="http://b.hatena.ne.jp/images/append.gif"
 style="border: none; display: inline; margin-left: 5px;"
 alt="このエントリーをはてなブックマークに追加"
 title="このエントリーをはてなブックマークに追加" width="16" height="12" /></a>

参考にしたのはたつをさんの日記NDO::Weblog

2005-04-05

Java からはてなフォトライフAtomAPIを使う

はてなの技術が今後目指す方向を読んだ。こういう方向性を明確に打ち出せるのがうらやましい。それに比べて自分のやっていることはなんとつまらなくて淋しいことか、と溜息が出てしまうのだった。

こちらの日記のコメントにも書いたけど、REST だの SOA だと騒いでるのは、ごくごく一部の(ちょっとだけ影響力のある)人たちだけで、ニュートラルな立場の人々はそんなことは関係なく次々とウェブサービスで面白いハックを送り出しているのだ。そして現在は、ニュートラルな側(google, amazon, hatena, etc...)が影響力を持つ時代になっている。かつてハードウェアベンダからマイクロソフトに影響力が移ったのと同じように。

僕はもうすぐ30になるけれど(ああ、ついに20代ともお別れか)次の10年を考えなければいけなさそうだ。僕はアーキテクチャの流儀(architectural style)としての REST には重要性があると思っているし、SOA にだって見るべきところがないわけではないと思っている。どちらも学問と現場の間で言えば学問よりの中間層となるだろう。アーキテクチャの流儀ってソフトウェア工学の言葉だしね。でもそれらを仕事を通じて実利を生み出せているのか不安にもなる。もちろん仕事の価値はそれだけではないが、僕にとってのエンジニアとしてのやりがいはそこなのだ。その学問と現場の間をつなぐような仕事がしたい、ということか。そういえば檜山さんのこの文書にも深く共感したのだった。

と、ここまではグチです。

本題は、はてなウェブサービスを Java から使うために必用なX-WSSE ヘッダを扱うライブラリがうまくみつけられなかったので(本当はws-fx の wss4j が妥当だろう)、自分で書いてしまった、というハナシです。といっても、吉松さんの C# 版のコードを参考に Java に移植しただけ…。commons httpclient と commons codec が必要です。言うまでもないけど、僕のパスワードはうそなので、そのまま使っても動かないはず。コメントないけど自由にコピペして使ってください。

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;


public class AtomTest {
  
  private HttpClient client;
  
  public AtomTest() {
    this.client = new HttpClient();
  }
  
  public void get(String url, String username, String password)
    throws HttpException, IOException {
    GetMethod get = new GetMethod(url);
    get.addRequestHeader("X-WSSE", getWsseHeaderValue(username, password));
    this.client.executeMethod(get);
    System.out.println(get.getStatusLine().toString());
    System.out.println(get.getResponseBodyAsString());
  }
  
  protected final String getWsseHeaderValue(String username, String password) {
    try {
      byte[] nonceB = new byte[8];
      SecureRandom.getInstance("SHA1PRNG").nextBytes(nonceB);

      SimpleDateFormat zulu = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
      zulu.setTimeZone(TimeZone.getTimeZone("GMT"));
      Calendar now = Calendar.getInstance();
      now.setTimeInMillis(System.currentTimeMillis());
      String created = zulu.format(now.getTime());
      byte[] createdB = created.getBytes("utf-8");
      byte[] passwordB = password.getBytes("utf-8");
    
      byte[] v = new byte[nonceB.length + createdB.length + passwordB.length];
      System.arraycopy(nonceB, 0, v, 0, nonceB.length);
      System.arraycopy(createdB, 0, v, nonceB.length, createdB.length);
      System.arraycopy(passwordB, 0, v, nonceB.length + createdB.length,
                       passwordB.length);

      MessageDigest md = MessageDigest.getInstance("SHA1");
      md.update(v);
      byte[] digest = md.digest();

      StringBuffer buf = new StringBuffer();
      buf.append("UsernameToken Username=\"");
      buf.append(username);
      buf.append("\", PasswordDigest=\"");
      buf.append(new String(Base64.encodeBase64(digest)));
      buf.append("\", Nonce=\"");
      buf.append(new String(Base64.encodeBase64(nonceB)));
      buf.append("\", Created=\"");
      buf.append(created);
      buf.append('"');
      return buf.toString();
    } catch (NoSuchAlgorithmException e) {
      throw new RuntimeException(e);
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
  }

  public static void main(String[] args) throws Exception {
    AtomTest test = new AtomTest();
    test.get("http://f.hatena.ne.jp/atom", "yohei", "hoehoe");
  }
}

ラベル: ,

2005-04-04

奥さんに REST をどう説明したかというと…

Ryan Tomayko の楽しくてためになる blog "How I explained REST to my wife..." を訳しました

ラベル: ,