2009-02-09

はてなダイアリーAtomPubレビュー: その3 設計編

はてなブックマーク   livedoor clip

さて、このシリーズも今回で最後です。遅れに遅れて申し訳ありません…ちなみに昨年の12/22付けで仕様書が改訂され、私が指摘したところが直っていました。どうもありがとうございます>中の人

最後は設計編です。

今回、私がはてなダイアリーAtomPubの仕様を見ていて、設計面で疑問に思ったのは次の2点です。

  • X-HATENA-PUBLISH HTTP ヘッダ
  • エントリ文書の対称性

以下ではそれぞれについて具体的に検討してみます。

X-HATENA-PUBLISHヘッダ

いくつかのブログでも指摘されていますが、はてなダイアリーAtomPubではapp:draft 要素を利用しません。

はてなダイアリーAtomPub仕様書によると、以下のような理由があるそうです。

はてなダイアリーAtomPubでは、AtomPubで規定されているapp:draft要素を使用しません。はてなダイアリーでは日記エントリと下書きエントリを別々に管理しています。そのため、日記エントリと下書きエントリを一つのコレクションとして扱い、app:draft要素によって下書きかどうかを区別するような構成は不自然になります。むしろ、下書きエントリを日記エントリとして公開するという操作を行う仕組みであるほうが自然であると考え、以下のような方法をとっています。

なるほど、コレクションを分ける際の実装上の都合なわけですね。

これは、これで一つの設計判断だと考えます。コレクション間のエントリのコピーや移動は AtomPub では定義されていませんので、何らかの拡張仕様が必要になります。WebDAV の MOVE を使うなど、マニアックな方法も考えられますが、独自ヘッダは悪くない判断だと思います。

ただし2点、よくない点があります。

1点目は、X-HATENA-PUBLISH の値の仕様です。このヘッダが取りうる値は「1」なのですが、いったいこれは何を意味するのでしょうか。おそらく内部的に Perl の “1″ としてそのまま実装されているのでしょうが、これはたとえば “true” にするなど、もう少し可読性を考慮した方がよいでしょう。

また、”1″ 以外の値を値を入れたときの挙動も不明です。たとえば “111″, “01″, “hoge” などを入れたらどうなるのでしょうか。

2点目は、PUT メソッドの挙動です。

はてなダイアリーAtomPubの仕様では、下書きを公開するときは既存の下書きエントリに対して X-HATENA-PUBLISH を 1 にした PUT を送ります。このリクエストが成功すると、レスポンスとして 201 Created が返り、Location ヘッダに公開されたブログコレクションのエントリが入ります。これは少し違和感を感じるところです。

HTTP/1.1 における PUT の仕様は以下のとおりです。

PUT メソッドは、同封されたエンティティを供給される Request-URI の元に保存するように要求する。 Request-URI が既に存在するリソースを参照している場合は、同封されるエンティティはオリジンサーバにあるそれの修正版とみなされるべきである。 Request-URI が既存のリソースを指していない場合に、その URI がリクエストしているユーザエージェントによって新しいリソースとして定義する事ができる時は、オリジンサーバはその URI にリソースを作成できる。新しいリソースが作成された場合、オリジンサーバは 201 (Created) レスポンスをもってユーザエージェントに知らせなければならない。既存のリソースが更新された場合は、リクエストが成功し終了した事を示すために 200 (OK) か 204 (No Content) のいずれかのレスポンスコードを送るべきである。

つまり PUT のレスポンスは

  • その URI が存在しない場合はリソースを新規作成して 201 を返す
  • その URI が存在する場合は、リソースを変更して 200 か 204 を返す

となります。これは SHALL (べきである)なので、絶対に従わなければならないことはありませんが、いずれにせよ既存の URI に対しての PUT で 201 が返るというのは、仕様上のグレーゾーンでクライアントを混乱させる可能性があります。

私だったらどうするか

もし私がこの機能を設計するなら以下のように考えます。

下書き機能は AtomPub の app:draft 要素に非常に近い(というかほぼ同じ)機能であるため、いかにこれを活かすかを考えます。今回の問題はドラフト状態を公開すると URI が変更になってしまうところなのですが、これをいかに違和感なくクライアントに教えるか、が課題です。

PUT すると URI が変更される(リソースが移動するイメージ)というのがクライアントからの一番の違和感だと思うので、そこをどうにかするようにしたいですね。そのためには、ドラフトの URI を残しつつ、そのリソースに別の URI (エイリアス)を付与するのが良いように思います。

これには HTTP に標準で付いてくる Content-Location ヘッダを使うことで解決できそうです。この方式を採用したときのリクエスト・レスポンスは以下のようになります。

PUT /yohei/atom/draft/12345678 HTTP/1.1
Host: d.hatena.ne.jp

<entry xmlns="http://www.w3.org/2005/Atom"
    xmlns:app="http://www.w3.org/2007/app">
  <title>テスト</title>
  <app:control>
    <app:draft>yes</app:draft>
  </app:control>
  ...
HTTP/1.1 200 OK
Content-Location: http://d.hatena.ne.jp/yohei/20081224/abcdefg

/draft 以下の URI も依然として有効ですが(おそらく作者だけがアクセスできるリソースになるでしょう)、ダイアリーの方のリソースも別名で有効になります。

もちろん、サーバ側の実装の都合で、ドラフトエントリを公開するとドラフトコレクションからは必ず消さないといけないのかもしれません。上記のような理想形で設計したとおりに実装できるわけではないですが、一つのヒントとして提案してみます。

エントリ文書の対称性

2点目はエントリ文書の対称性についてです。
現在の仕様では、ブログコレクションで日記エントリを更新するとき、以下の
ようなリクエストを送ります。

PUT /yohei/atom/blog/20090203/xxx HTTP/1.1
Host: d.hatena.ne.jp
Content-Type: application/atom+xml; type=entry; charset=utf-8

<entry xmlns="http://www.w3.org/2005/Atom">
  <updated>2009-02-03T00:00:00Z</updated>
  <id>tag:d.hatena.ne.jp,2008:diary-yohei-20081226-p1
  <author><name>yohei</name></author>
  <title>test</title>
  <content type="text">this is a test</content>
</entry>

これに対して、以下のようなレスポンスが返ってきます。

HTTP/1.0 200 OK
Date: Wed, 04 Feb 2009 04:13:59 GMT
Server: Apache/2.2.3 (CentOS)
Content-Length: 694
Content-Type: application/atom+xml;type=entry; charset=utf-8

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <updated>2008-12-26T00:00:00+09:00</updated>
  <published>2008-12-26T00:00:00+09:00</published>
  <app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-26T00:00:00+09:00</app:edited>
  <id>tag:d.hatena.ne.jp,2008:diary-yohei-20081226-p1</id>
  <link rel="edit" href="http://d.hatena.ne.jp/yohei/atom/blog/20081226/p1"/>
  <link rel="alternate" type="text/html" href="http://d.hatena.ne.jp/yohei/20081226/p1"/>
  <author>
    <name>yohei</name>
  </author>
  <title>test</title>
  <content type="html">
                &lt;div class="section"&gt;
                        &lt;p&gt;this is a test&lt;/p&gt;
                &lt;/div&gt;
</content>
</entry>

このリソースを再び GET してみると以下のようになります。

GET http://d.hatena.ne.jp/yohei/atom/blog/20081226/p1 HTTP/1.1
Host: d.hatena.ne.jp
HTTP/1.0 200 OK
Date: Wed, 04 Feb 2009 05:13:52 GMT
Server: Apache/2.2.3 (CentOS)
Content-Length: 793
Content-Type: application/atom+xml;type=entry; charset=utf-8

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <updated>2008-12-26T00:00:00+09:00</updated>
  <published>2008-12-26T00:00:00+09:00</published>
  <app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-26T00:00:00+09:00</app:edited>
  <id>tag:d.hatena.ne.jp,2008:diary-yohei-20081226-p1
  <link rel="edit" href="http://d.hatena.ne.jp/yohei/atom/blog/20081226/p1"/>
  <link rel="alternate" type="text/html" href="http://d.hatena.ne.jp/yohei/20081226/p1"/>
  <author>
    <name>yohei</name>
  </author>
  <title>test</title>
  <content type="html">
                &lt;div class="section"&gt;
                        &lt;p&gt;this is a test&lt;/p&gt;
                &lt;/div&gt;
</content>
  <hatena:syntax xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#">this is a test</hatena:syntax>
</entry>

ブログコレクションのエントリを編集するときは、以下のことに気をつける必要があります。

  • 追加・更新を行うときは /entry/content/@type は “text” ではてな記法を入れる
  • サーバから取得できる /entry/content は @type=”html” ではてな記法がHTML にレンダリングされたものが入り、/entry/hatena:syntax にはてな記法が入る

これはクライアント側ではてな記法を入れる要素について注意しながら、はてな独自のロジックを実装しなければならない点で、あまり良い設計ではないと言えるでしょう。

この問題を解決する方法はいくつか考えられますが、完璧なソリューションは存在しないと思います。私が即興で考えたソリューションのそれぞれのメリット・デメリットを挙げておきます。

/entry/content に常にはてな記法を入れる

Pros
既存の AtomPub クライアントをほぼそのまま利用可能
Cons
既存のブログクライアントのユーザははてな記法を使うことを理解しなければならない
フィードをフィードリーダーで見たときにはてな記法が出てしまう

/entry/hatena:syntax を常に使うようにする

Pros
content を HTML にできる
Cons
AtomPub クライアントが hatena:syntax を理解しなければ更新ができない

まとめ

先日、会社の超先輩エンジニア(ソフトだけじゃなくてエレキよりの設計も含めて全般されてきた方です)の方と話をしたのですが、そのときに「設計はバランスだよ」という言葉をもらいました。

今回の件でもわかるとおり、設計というのはあちらを立てればこちらが立たず、ということが多く、全てを満足させることは不可能です。

私はよく「REST 的に理想的な設計にするにはどうしたらいいんでしょう」というような質問を受けるのですが、正直なところ理想ばかり追いかけても仕方がないだろう、と思います。REST はあくまでも設計のためのヒントなのであり、それ自体が目的になってしまったら本末転倒です。

高い理想をバックグラウンドに、現実的でバランスの取れた設計をするのが優れたエンジニアなのではないでしょうか。

2008-10-27

はてなダイアリーAtomPubレビュー: その2 ドキュメンテーション編

はてなブックマーク   livedoor clip

その1を公開してからだいぶ時間が経ってしまいましたが、その2を公開します。今回はドキュメンテーション編です。

レビュー対象ははてなダイアリーAtomPubの仕様書です。普段私が業務で仕様書をレビューするときに気をつけている観点をご紹介しながら、いくつか指摘をしてみます。

なお、レビューの指摘はどうしても細かくなってしまうので、粗探し的と感じられてしまうかもしれませんが、技術的な完成度を上げるためには必要な作業なのでご容赦ください。

基本的な文章チェック

まず、仕様書に記述されている文章の「てにをは」や文法レベルでのチェックをします。表記ゆれなども含まれます。

今回の仕様書は、たとえば以下のような記述がありました。

  • 「ヘッダ」と「ヘッダー」、「XML文書」と「XML文章」、「はてなID」と「はてなアカウントのid」などの表記ゆれ。document に対する訳語は通常は「文書」を用います
  • 「~することができます」という冗長表現。私もよくやってしまうのですが、これは「~できる」にとした方がシンプルで読みやすくなります
  • 「GETをリクエストする」と「リクエストXML文章をPOSTする」。これも表記ゆれの一種ですが、私だったら「GETする」「XML文書をPOSTする」にします
  • 単純なコピペミスっぽいですが、下書きコレクションの段落で、「XXXXXXXXXXは実際には」で切れてしまっている文章がありました

こういった基本的な文章のバグは、ワードの文書校正ツールなどを使うと簡単に検出できるものも多いので、機械的に処理するのがおすすめです。

必須項目のチェック

次に、仕様書として必要な項目が足りているかを確認します。

基本設計仕様書やテスト仕様書など、フォーマットがある程度決っているものであれば、それに沿っているかをチェックします。今回の場合は Web API の仕様書なので、これが標準、というフォーマットはないと思いますが、以下の項目が足りないかなと思いました。

目次
仕様書は全体が長いので、さっと目を通せるように目次を入れる方がよいでしょう
エラー仕様
Web API の場合、エラー仕様というのはなかなか書きづらいのですが、それ
でも不正な操作に対して、API がどのように反応するかを一言記述しておく方
がよいと思います
セキュリティに関する考察
RFC などでは必須になっています

変更点、拡張点のチェック

AtomPub のように、ベースとなる仕様書があり、それに基づいた形でAPIを設計する場合は、オリジナルとの変更点や拡張点を明記する方がよいでしょう。逆に言うとオリジナルの方で詳しく記述されている部分は、概要だけを書いて詳細はオリジナルを参照してもらう方がよいと思います。

今回のAPI仕様でいえば、変更点は X-HATENA-PUBLISH ヘッダ、拡張点は hatena:syntax 要素になります。

オリジナルの仕様を変更した場合は、なぜそのような設計になったのか、その理由を書いておく方が親切です。特にある程度標準に従っている場合、利用者はオリジナルの方法に慣れているため、変更点はつまづきポイントになるからです。

この理由とはたとえば、レガシーシステムの実装上の都合であるとか、開発効率の問題であるとか、はたまたオリジナル仕様が間違っている、などが考えられます。残念ながら、現状のはてなダイアリーAtomPubの仕様では、なぜ AtomPub 標準の app:draft 要素ではなく X-HATENA-PUBLISH が必要だったのかの記述はありませんでした。

拡張点については、はてなダイアリーAtomPubの仕様では hatena:syntax 要素がはてな記法を入れるために導入されたことが明記されているので問題ありませんね。

技術的なチェック

最後に、技術的な正確性を検証します。

今回、私が気づいたものとしては以下の点があります。

  • content/@type が text/html なのに、要素内容のタグがエスケープされていません(実装は正しくされています)
  • パラメータ付きURIは URI Templates の記法を利用した方がよいでしょう(/はてなID/atom/draft/XXXXXXXXXX → /{はてなID}/atom/draft/{entry-id})
  • HTTP/1.1 201 CREATED の Reason-Phrase は Created が一般的です(CREATEDでもHTTP仕様としては間違いではありません)

まとめ

技術文書にはプログラムだけでは伝えきれない設計の意図を伝えるという目的があります。プログラムもそうですが、文書もひとりで書くだけではなくレビューすることが大切です。人に読んでもらうことで初めてわかることも多々あるので、ソースコードレビューと同じくらいドキュメントのレビューにも力を入れるべきです。

また、文章の書き方自体の勉強も大切です。私も偉そうなことは言えないのですが、学生のころにかずさんの正確な文章の書き方を読んだり、檜山さん(プロのテクニカルライター)のライティングスキルを目の当たりにしたりして(参考)、技術者のライティングスキルの重要性を認識しました。

ということで、このエントリでライティングスキルもプログラミングスキルと同じくらい重要である、と認識してくれる人が増えることを願っています。

ちなみにこのレビューシリース、まだ続きます。

2008-09-25

はてなダイアリー AtomPub レビュー: その1 実装編

はてなブックマーク   livedoor clip

はてなさんがダイアリーAtomPubインターフェースをリリースしていました。

私は AtomPub が大好きなので、少しだけ試してみました。簡単にレビューを書こうと思ってエントリを起したのですが、意外と長くなりそうなので3部構成でお送りします。まずは実装編です。

認証

とりあえず普通のGETリクエストをサービス文書に送ってみます。http://d.hatena.ne.jp/{hatena-id}/atom がサービス文書の URI です。

GET http://d.hatena.ne.jp/yohei/atom HTTP/1.1
Accept: */*
Host: d.hatena.ne.jp
HTTP/1.0 401 Unauthorized
Date: Fri, 19 Sep 2008 07:00:10 GMT
Server: Apache/2.2.3 (CentOS)
WWW-Authenticate: WSSE profile="UsernameToken"
Content-Length: 16
Content-Type: text/plain;charset=utf-8
Set-Cookie: b=xxx; path=/; expires=Thu, 14-Sep-28 05:05:06 GMT; domain=.hatena.ne.jp
Vary: Accept-Encoding

401 Unauthorized

401 が返ってきました。WWW-Authenticate ヘッダによれば、WSSE 認証が必要なようです。

レスポンスヘッダで一つ気になるのが、なぜか Set-Cookie ヘッダがあることです。Cookie 認証のなごりでしょうか…。セキュリティの観点からもこのヘッダはなくした方がよさそうです。ちなみに expires の年が2桁で 28 なのもちょっと困りますね。UIの方は普通の Cookie を返すので、何かのバグなんでしょうか。以下の例でも全て Set-Cookie ヘッダが返ってくるのですが、省略しています。

サービス文書

ということで、X-WSSE ヘッダを加えてサービス文書を GET してみます。以下、全てのリクエストで認証が必要ですが、長いので、次以降の例ではこのヘッダは省略します。

GET http://d.hatena.ne.jp/yohei/atom HTTP/1.1
Accept: */*
X-Wsse: UsernameToken Username="yohei", PasswordDigest="foo", Nonce="bar", Created="2008-09-19T22:53:55+09:00"
Host: d.hatena.ne.jp
HTTP/1.0 200 OK
Date: Fri, 19 Sep 2008 05:05:06 GMT
Server: Apache/2.2.3 (CentOS)
Content-Length: 676
Content-Type: application/atomsvc+xml;charset=utf-8
Vary: Accept-Encoding

<?xml version="1.0" encoding="utf-8"?>
<service xmlns="http://www.w3.org/2007/app">
  <workspace>
    <atom:title xmlns:atom="http://www.w3.org/2005/Atom">Hatena::Diary - yohei</atom:title>
    <collection href="http://d.hatena.ne.jp/yohei/atom/draft">
      <atom:title xmlns:atom="http://www.w3.org/2005/Atom">yoheiさんの下書き</atom:title>
      <accept>application/atom+xml;type=entry</accept>
    </collection>
    <collection href="http://d.hatena.ne.jp/yohei/atom/blog">
      <atom:title xmlns:atom="http://www.w3.org/2005/Atom">yoheiさんの日記</atom:title>
      <accept>application/atom+xml;type=entry</accept>
    </collection>
  </workspace>
</service>

サービス文書が取れました。はてなダイアリーAtomPub では二つのコレクションリソースが用意されているのがわかります。draftコレクション(http://d.hatena.ne.jp/{hatena-id}/atom/draft)とblogコレクション(http://d.hatena.ne.jp/{hatena-id}/atom/blog)です。両方とも、Atom エントリ文書が POST できることがわかります。

ちなみに HEAD してみると…

HEAD http://d.hatena.ne.jp/yohei/atom HTTP/1.1
Accept: */*
Host: d.hatena.ne.jp
HTTP/1.0 200 OK
Date: Fri, 19 Sep 2008 05:07:26 GMT
Server: Apache/2.2.3 (CentOS)
Content-Length: 676
Content-Type: application/atomsvc+xml;charset=utf-8
Vary: Accept-Encoding

nil

HEAD リクエストへのレスポンスなのに、ボディに “nil” とあるのが残念です。

コレクションリソース

次にコレクションリソースです。まずは GET してみました。

GET http://d.hatena.ne.jp/yohei/atom/blog HTTP/1.1
Accept: */*
Host: d.hatena.ne.jp
HTTP/1.0 200 OK
Date: Fri, 19 Sep 2008 05:34:08 GMT
Server: Apache/2.2.3 (CentOS)
Content-Length: 20722
Content-Type: application/atom+xml;charset=type=feed
Vary: Accept-Encoding

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <updated>2006-11-24T00:00:00+09:00</updated>
  <id>tag:d.hatena.ne.jp,2006:diary-yohei</id>
  <title>傭兵日記</title>
  <author>
    <name>yohei</name>
  </author>
  <link rel="self" href="http://d.hatena.ne.jp/yohei/atom/blog"/>
  <link rel="next" href="http://d.hatena.ne.jp/yohei/atom/blog?page=2"/>
  <entry>
  ...

プレーンな Atom フィードが返ってきました。rel=”next” なリンクもありますね。これは便利です。

ということで、2ページ目を GET してみました。

GET http://d.hatena.ne.jp/yohei/atom/blog?page=2 HTTP/1.1
Accept: */*
Host: d.hatena.ne.jp
HTTP/1.0 200 OK
Date: Fri, 19 Sep 2008 07:06:51 GMT
Server: Apache/2.2.3 (CentOS)
Content-Length: 24964
Content-Type: application/atom+xml;charset=type=feed
Vary: Accept-Encoding
X-Cache: MISS from unknown

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <updated>2006-11-24T00:00:00+09:00</updated>
  <id>tag:d.hatena.ne.jp,2006:diary-yohei</id>
  <title>傭兵日記</title>
  <author>
    <name>yohei</name>
  </author>
  <link rel="self" href="http://d.hatena.ne.jp/yohei/atom/blog?page=2"/>
  <link rel="next" href="http://d.hatena.ne.jp/yohei/atom/blog?page=3"/>
  <entry>
...

2ページ目のリソースからは3ページ目にリンクしてますね。ここで惜しいのは、rel=”prev” なリンクがないことです。リンクが片道通行になっちゃってます。

もうひとつ気になったのはフィードの id です。tag スキームを使っているのですが、これに含まれる年がフィードに含まれる最新エントリの年になるようなのです。MT 3.x で同様の問題がありましたが、idは一定の値でないとまずいので、たとえば2008をハードコーディングした方がよいのではないかなと思います。

それから、Content-Type が

application/atom+xml;charset=type=feed

なんですが、これは正しくは

application/atom+xml;charset=utf-8;type=feed

ですね。

ちなみに、コレクションでも HEAD リクエストを送ってみました。

HEAD http://d.hatena.ne.jp/yohei/atom/draft HTTP/1.1
Accept: */*
Host: d.hatena.ne.jp
HTTP/1.0 405 Method Not Allowed
Date: Fri, 19 Sep 2008 05:16:12 GMT
Server: Apache/2.2.3 (CentOS)
Allow: GET, POST
Content-Length: 22
Content-Type: application/atom+xml;charset=type=entry
Vary: Accept-Encoding
X-Cache: MISS from unknown

nil

おおー、405 が返ってきました。しかもちゃんと Allow ヘッダもあります。ただ、Content-Type のパラメータが charset=type=entry なのはおかしいですね。entry ではないですし、charset=utf-8;type=feed であるべきです。

エントリのPOST

ではエントリを POST してみましょう。まずは draft コレクションに POST してみました。

POST http://d.hatena.ne.jp/yohei/atom/draft HTTP/1.1
Accept: */*
Content-Type: application/atom+xml;type=entry;charset=utf-8
Content-Length: 131
Host: d.hatena.ne.jp

<entry xmlns="http://www.w3.org/2005/Atom">
<title>test</title>
<content type="text">- test
-てすと</content>
</entry>
HTTP/1.0 201 Created
Date: Fri, 19 Sep 2008 07:45:24 GMT
Server: Apache/2.2.3 (CentOS)
Location: http://d.hatena.ne.jp/yohei/atom/draft/1221810325
Content-Length: 549
Content-Type: application/atom+xml;charset=type=entry
Vary: Accept-Encoding

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <id>tag:d.hatena.ne.jp,2008:diary-draft-yohei-1221810325</id>
  <link rel="edit" href="http://d.hatena.ne.jp/yohei/atom/draft/1221810325"/>
  <author>
    <name>yohei</name>
  </author>
  <title>test</title>
  <updated>2008-09-19T16:45:25+09:00</updated>
  <published>2008-09-19T16:45:25+09:00</published>
  <app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-19T16:45:25+09:00</app:edited>
  <content type="text/plain">- test
-てすと</content>
</entry>

無事エントリが作成されます。ちなみに、content 要素の内容は draft コレクションでははてな記法の文字列が text/plain 形式で入り、blog コレクションではhtmlに変換済みの文字列が text/html で入ります。そして、blog コレクションでのはてな記法の文字列は hatena:syntax 要素に入ってくるそうです。これは最初わからず、ちょっとはまりました…

ただ、ちょっと気になるのは content 要素の type 属性の値です。RFC 4287 では text/html/xhtml or MIME タイプを取ることになっており、ここでは text/plain ではなく text が、そして text/html ではなく html が望ましいですね。

その他の操作

とりあえず仕様書どおりに実装すれば PUT/DELETE はできました。blog コレクションでも PUT するときは content 要素にはてな記法を入れるというのにははまりましたが…。これについては設計編で詳しく触れたいと思います。

それから、ちょっとした不正 URI のテスト(全てGET)をしてみましたが、以下のような結果でした。

  • http://d.hatena.ne.jp/{hatena-id}/ato -> 302
  • http://d.hatena.ne.jp/{hatena-id}/atom/blo -> 404
  • http://d.hatena.ne.jp/{hatena-id}/atom/blog/20 -> 404
  • http://d.hatena.ne.jp/{hatena-id}/atom/blog/{yyymmdd}/foo -> 403

これらは全て 404 が望ましいと思います。

また、全体的に Content-Type が正しく設定されていない場面がみうけられます。

たとえば DELETE のレスポンスが空なのに text/html;charset=utf-8 だったり、400/403 が返るときにプレーンテキストなのにapplication/atom+xml;type=entry が返ってきたりなどです。

この辺はテストケースの不足だと思いますが、AtomPub には Tim Bray が作った Ape や Joe Gregorio の Atom Publishing Protocol Test Suite など、テストケースが用意されているので、これらを使ってテストするといいと思います。

2008-02-18

AtomPub Interop 2008 in Tokyo に参加してきました。

はてなブックマーク   livedoor clip

前回に引き続き、今月(2008/2)の12日午後に行われた AtomPub の Interop に参加してきました。
今回は全部で 6 社から 13 名が参加していましたが、リコーからは 5名、リコーソフトウエアからも 1 名参加していたので、非常にリコー率が高くなってしまいました。yoheiさんに影響されて社内でも AtomPub への関心が高まっていますね。

今回もホスト役をしていただいたNTTコミュニケーションズの朝倉さん、坂野さん、ありがとうございました。

事業部から参加した二人と私は前回と同じく Java ME のサーバとクライアントを持って参加したのですが、yohei さんは curl(一般的なコマンドラインのHTTPクライアント)で、研究所から参加したもう一人はその場で perl のクライアントを書いていました。参加の目的は相互接続試験というよりも、AtomPub 周辺の議論をするためだったようですね。ちなみにリコーソフトウエアの方は Ruby on Rails のサーバを持ってきていました。

私は私用で最後までいられなかったのですが、参加者の皆さんそれぞれバグが発見されたり、仕様で明確に決まっていない部分の議論ができたりと有意義に過ごされたようです。

最後になってしまいましたが、補足しておくと Interop とは Interoperability test、つまり相互接続試験のことです。AtomPub のように通信系の仕様の場合、その実装同士が通信できないとお話にならないので、各社が開発中の製品などを持ち寄ってお互いに通信できるかどうかのテストをしたり、できない場合にその場でバグを修正したりします。AtomPub の場合は通信相手はお互いに PC の場合が多いので今回の Interop も皆さんノート PC を持ち寄っていましたが、bluetooth などの Interop ではデジタルカメラや携帯電話などを持ってくることも多いので、発売前の製品は布などで隠した状態のまま確認したりすることもあるようです。