はてなダイアリーAtomPubとはてな記法
TODO: ampleeを使ってAPIをたたいてみる
本ドキュメントに関する注意事項
本ドキュメントははてなダイアリーにおける Atom Publishing Protocol の仕様を解説するものです。主にはてなスタッフがその作成と更新を行っています。
変更履歴
Atom Publishing Protocol とは
Atom Publishing Protocol(以下 AtomPub) はウェブリソースを公開、編集するためのアプリケーション・プロトコル仕様です。はてなダイアリーのAtomPubと通じて、開発者ははてなダイアリーの日記を参照、投稿、編集、削除するようなオリジナルのアプリケーションを作成することができます。
AtomPub について詳しくは http://www.ietf.org/rfc/rfc5023.txt (英語)などを参照してください。
はてなダイアリーにおけるAtomPub実装の概要
HTTP の GET/POST/PUT/DELETE を特定のURIに対してリクエストし、そのリクエストに規定のXML文書を加えて送信することでインタフェースが用意している操作を行うことができます。
AtomPubには特定の操作の対象の集合を表す「コレクション」と個々の操作の対象を表す「メンバ」があります。コレクションとメンバはそれぞれにURIを持ち、そのURIに対して操作を行います。例えば、はてなダイアリーの日記エントリーのコレクションとメンバのURIは以下のようになります。
- コレクションURI: http://d.hatena.ne.jp/はてなID/atom/blog
- メンバURI: http://d.hatena.ne.jp/はてなID/atom/blog/20080101/XXXXXXXXXX (XXXXXXXXXXは実際には数値)
一部の操作はそのレスポンスとして規定のXML文書を返却します。また、下書きエントリーの公開操作を実現するためにAtomPubを拡張しています。
以下、はてなダイアリーAtomPubの詳細を解説します。
認証
はてなダイアリーAtomPubを利用するために、クライアントはWSSE認証を行う必要があります。
WSSE認証
AtomPubに良く用いられるWSSE認証が利用できます。WSSE認証の詳細に関しては http://www-128.ibm.com/developerworks/webservices/library/ws-secure/ (英語) を参照してください。ここではWSSE認証についての必要事項を簡単に解説します。
WSSE認証はHTTPのX-WSSEヘッダを用いて認証用文字列を送信する認証手段です。WSSE認証用文字列にはユーザー名とパスワードが含まれます。このとき、パスワードはSHA1アルゴリズムによって暗号化されたダイジェストとして送信されるため、HTTP基本認証などに比べてセキュアな認証が可能です。
送信するX-WSSEヘッダのサンプルは以下のようになります。
X-WSSE: UsernameToken Username="hatena", PasswordDigest="ZCNaK2jrXr4+zsCaYK/YLUxImZU=", Nonce="Uh95NQlviNpJQR1MmML+zq6pFxE=", Created="2005-01-18T03:20:15Z"
- Username
- ユーザー名。(はてなアカウントのid)
- Nonce
- HTTPリクエスト毎に生成したセキュリティ・トークン*1
- Created
- Nonceが作成された日時をISO-8601表記で記述したもの
- PasswordDigest
- Nonce, Created, パスワード(はてなアカウントのパスワード)を文字列連結しSHA1アルゴリズムでダイジェスト化して生成された文字列を、Base64エンコードした文字列
具体的な実装方法については、はてなフォトライフAtomAPIを参照してください。
文字コード
はてなダイアリーAtomPubでは文字コードとしてUTF-8を利用します。リクエストXML、レスポンスXML共にUTF-8として扱ってください。
はてなダイアリーの他の場所では文字コードとしてEUC-JPを利用していることが多いので、まちがえないよう注意してください。
サービス文書
はてなダイアリーAtomPubで操作できるコレクションの一覧を含むサービス文章を取得することができます。
http://d.hatena.ne.jp/はてなID/atom
リクエスト
GET /はてなID/atomレスポンス
HTTP/1.1 200 OK
Content-Type: application/atomsvc+xml; charset=utf-8<?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 - はてなID</atom:title>
<collection href="http://d.hatena.ne.jp/はてなID/atom/draft">
<atom:title xmlns:atom="http://www.w3.org/2005/Atom">はてなIDさんの下書き</atom:title>
<accept>application/atom+xml;type=entry</accept>
</collection>
<collection href="http://d.hatena.ne.jp/はてなID/atom/blog">
<atom:title xmlns:atom="http://www.w3.org/2005/Atom">はてなIDさんの日記</atom:title>
<accept>application/atom+xml;type=entry</accept>
</collection>
</workspace>
</service>ブログ コレクション
はてなダイアリーの日記エントリーを操作するためのコレクションです。日記エントリーの投稿、取得、編集、削除、一覧の取得を行うことができます。コレクションURI、およびメンバURIは以下になります。
- コレクションURI: http://d.hatena.ne.jp/はてなID/atom/blog
- メンバURI: http://d.hatena.ne.jp/はてなID/atom/blog/20080101/XXXXXXXXXX (XXXXXXXXXXは実際には数値)
日記エントリー一覧の取得
コレクションURIに対してGETをリクエストすることで、日記エントリー一覧を取得することができます。一度に20件のエントリーを取得できます。また、pageパラメータに数値を指定することで、20件目以降のエントリーを取得することもできます。
リクエスト
GET /はてなID/atom/blog
GET /はてなID/atom/blog?page=2レスポンス
指定ページに対応した Atom Feed 文章が返却されます。ここでは省略します。
日記エントリーの投稿
コレクションURIに対してリクエストXML文章をPOSTすることで、日記エントリーを投稿することができます。
リクエスト
- title要素 日記エントリーのタイトル
- content要素 はてな記法で記述された日記エントリーの本文
- type属性 text/plain
- updated要素 日記エントリーを投稿する日時を指定します。この指定を行わなかった場合、投稿を行った日時が利用されます。
POST /はてなID/atom/blog<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://purl.org/atom/ns#">
<title>日記エントリータイトル</title>
<content type="text/plain">
日記エントリー本文
- はてな
- 記法
</content>
<updated>2008-01-01T00:00:00+09:00</updated>
</entry>レスポンス
HTTP/1.1 201 CREATED
Content-Type: application/atom+xmlcharset=type=entry
Location: http://d.hatena.ne.jp/はてなID/atom/blog/20080101/XXXXXXXXXX<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<id>tag:d.hatena.ne.jp,2008:diary-はてなID-20080101-XXXXXXXXXX</id>
<link rel="edit" href="http://d.hatena.ne.jp/はてなID/atom/blog/20080101/XXXXXXXXXX"/>
<link rel="alternate" type="text/html" href="http://d.hatena.ne.jp/はてなID/20080101/XXXXXXXXXX"/>
<author>
<name>はてなID</name>
</author>
<title>日記エントリータイトル</title>
<updated>2008-01-01T00:00:00+09:00</updated>
<published>2008-01-01T00:00:00+09:00</published>
<app:edited xmlns:app="http://www.w3.org/2007/app">2008-01-01T00:00:00+09:00</app:edited>
<content type="text/html">
<div class="section">
<p>'日記エントリー本文'</p>
<ul>
<li> はてな</li>
<li> 記法</li>
</ul></div>
</content>
</entry>日記エントリーの取得
メンバURIに対してGETをリクエストすることで、日記エントリーを取得することができます。
リクエスト
GET /はてなID/atom/blog/20080101/XXXXXXXXXXレスポンス
- レスポンスは正常時にHTTPステータス200を返します。
- レスポンスXML文書はhatena名前空間(http://www.hatena.ne.jp/info/xmlns#)によって拡張されています。展開される前のはてな記法が格納されています。
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<id>tag:d.hatena.ne.jp,2008:diary-はてなID-20080101-XXXXXXXXXX</id>
<link rel="edit" href="http://d.hatena.ne.jp/はてなID/atom/blog/20080101/XXXXXXXXXX"/>
<link rel="alternate" type="text/html" href="http://d.hatena.ne.jp/はてなID/20080101/XXXXXXXXXX"/>
<author>
<name>はてなID</name>
</author>
<title>日記エントリータイトル</title>
<updated>2008-01-01T00:00:00+09:00</updated>
<published>2008-01-01T00:00:00+09:00</published>
<app:edited xmlns:app="http://www.w3.org/2007/app">2008-01-01T00:00:00+09:00</app:edited>
<content type="text/html">
<div class="section">
<p>'日記エントリー本文'</p>
<ul>
<li> はてな</li>
<li> 記法</li>
</ul></div>
</content>
<hatena:syntax xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#">'日記エントリー本文'
- はてな
- 記法</hatena:syntax>
</entry>
日記エントリーの編集
メンバURIに対してリクエストXML文章をPUTすることで、日記エントリーを編集することができます。投稿された日記エントリーの日時は投稿を行った日時になります。
リクエスト
- title要素 日記エントリーのタイトル
- content要素 はてな記法で記述された日記エントリーの本文
- type属性 text/plain
- updated要素 日記エントリーを投稿する日時を指定します。この指定を行わなかった場合、投稿を行った日時が利用されます。
PUT /はてなID/atom/blog/20080101/XXXXXXXXXX<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://purl.org/atom/ns#">
<title>あたらしい日記エントリータイトル</title>
<content type="text/plain">
あたらしい日記エントリー本文
- はてな
- 記法
</content>
<updated>2008-01-01T00:00:00+09:00</updated>
</entry>レスポンス
HTTP/1.1 200 OK
Content-Type: application/atom+xmlcharset=type=entry<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<id>tag:d.hatena.ne.jp,2008:diary-はてなID-20080101-XXXXXXXXXX</id>
<link rel="edit" href="http://d.hatena.ne.jp/はてなID/atom/blog/20080101/XXXXXXXXXX"/>
<link rel="alternate" type="text/html" href="http://d.hatena.ne.jp/はてなID/20080101/XXXXXXXXXX"/>
<author>
<name>はてなID</name>
</author>
<title>あたらしい日記エントリータイトル</title>
<updated>2008-01-01T00:00:00+09:00</updated>
<published>2008-01-01T00:00:00+09:00</published>
<app:edited xmlns:app="http://www.w3.org/2007/app">2008-01-01T00:00:00+09:00</app:edited>
<content type="text/html">
<div class="section">
<p>'あたらしい日記エントリー本文'</p>
<ul>
<li> はてな</li>
<li> 記法</li>
</ul></div>
</content>
</entry>日記エントリーの削除
メンバURIに対してDELETEをリクエストすることで、日記エントリーを削除することができます。
リクエスト
DELETE /はてなID/atom/blog/20080101/XXXXXXXXレスポンス
HTTP/1.1 200 OK下書き コレクション
はてなダイアリーの下書きを操作するためのコレクションです。下書きエントリーの投稿、取得、編集、削除、一覧の取得、および日記エントリーとしての公開を行うことができます。コレクションURI、およびメンバURIは以下になります。
- コレクションURI: http://d.hatena.ne.jp/はてなID/atom/draft
- メンバURI: http://d.hatena.ne.jp/はてなID/atom/draft/XXXXXXXXXX (XXXXXXXXXXは実際には
下書きコレクションの操作は基本的にブログコレクションと同等なため詳しい説明は省略します。返却されるAtom Entryのcontent要素に含まれるのがはてな記法になっている部分が異なっています。
下書きコレクションでは、AtomPub を拡張し、下書きを公開する操作を提供しています。
下書きエントリーの日記への公開
メンバURIに対してX-HATENA-PUBLISHヘッダを付与してPUTすることで、メンバURIで指定した下書きをもとに日記エントリーを投稿することができます。投稿された日記エントリーの日時は投稿を行った日時になります。
リクエスト
- X-HATENA-PUBLISH ヘッダに1を含めます。
PUT /はてなID/atom/blog/20080101/XXXXXXXX
X-HATENA-PUBLISH: 1レスポンス
実際のレスポンスの例はブログコレクションの日記エントリーの投稿を参照してください。
はてなダイアリー AtomPub を利用したプログラムの例
Perlを用いた例
CPANモジュールのXML::Atom::ClientはAtomPubクライアントを実装するための、WSSE認証やリクエスト、レスポンスに必要なXML文書の組み立てなどを抽象化したモジュールです。
XML::Atom::Clientを用いて、はてなダイアリーに日記を投稿するサンプルコードは以下です。
#!/usr/bin/env perl
use strict;
use warnings;use XML::Atom::Entry;
use XML::Atom::Client;my $username = shift or die "need username";
my $password = shift;my $PostURI = "http://d.hatena.ne.jp/$username/atom/blog";
my $client = XML::Atom::Client->new;
$client->username($username);
$client->password($password);my $entry = XML::Atom::Entry->new;
$entry->title('テスト日記だよー');
$entry->content(<<'ENDCONTENT');
わーい、はてな記法もかけるぞー
- こんな
- ふうに
- ね
ENDCONTENT
my $EditURI = $client->createEntry($PostURI, $entry)
or die $client->errstr;print $EditURI;
XML::Atom::Client はWSSE認証を抽象化しているため、username/passwordメソッドでそれぞれをセットするだけで認証を通過できます。また、XML文書の組み立てはXML::Atom::Entryインスタンスを生成して行い、それを最後にXML::Atom::Clientインスタンスに渡せば完了です。
$ perl atompost.pl はてなID passwordとすることで実行できます。
Rubyを用いた例
Ruby から API を利用するには、atomutil ライブラリを利用することによって投稿することが可能です。
まず、atomutil ライブラリを拡張し、X-Hatena-Publish に対応させ、下書きからの投稿を行えるようにします。
require 'rubygems'
require 'atomutil'module Atompub
class HatenaClient < Client
def publish_entry(uri)
@hatena_publish = true
update_resource(uri, ' ', Atom::MediaType::ENTRY.to_s)
ensure
@hatena_publish = false
endprivate
def set_common_info(req)
req['X-Hatena-Publish'] = 1 if @hatena_publish
super(req)
end
end
endauth = Atompub::Auth::Wsse.new :username => 'はてなID', :password => 'hatena_password'
client = Atompub::HatenaClient.new :auth => auth
service = client.get_service 'http://d.hatena.ne.jp/%s/atom' % config[:username]
collection_uri = service.workspace.collections[1].hrefentry = Atom::Entry.new(
:title => 'My Entry Title',
:updated => Time.now
)entry.content = <<EOF
エントリー本文だよ
EOFputs client.create_entry collection_uri, entry
エントリー下書き投稿は、collection_uri を変更するだけです。
collection_uri = service.workspace.collections[0].href
puts client.create_entry collection_uri, entry # 下書き投稿下書き投稿からパブリッシュするには、HatenaClient#publish_entry を使います
client.publish_entry entry.edit_link
ricollab Web Tech Blog ≫ Blog Archive ≫ はてなダイアリー AtomPub レビュー: その1 実装編
はてなさんがダイアリーの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.jpHTTP/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-Encoding401 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.jpHTTP/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.jpHTTP/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-EncodingHEAD リクエストへのレスポンスなのに、ボディに “nil” とあるのが残念です。
コレクションリソース
次にコレクションリソースです。まずは GET してみました。
GET http://d.hatena.ne.jp/yohei/atom/blog HTTP/1.1
Accept: */*
Host: d.hatena.ne.jpHTTP/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.jpHTTP/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.jpHTTP/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おおー、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 など、テストケースが用意されているので、これらを使ってテストするといいと思います。