本ドキュメントははてなダイアリーにおける Atom Publishing Protocol の仕様を解説するものです。主にはてなスタッフがその作成と更新を行っています。
Atom Publishing Protocol(以下 AtomPub) はウェブリソースを公開、編集するためのアプリケーション・プロトコル仕様です。はてなダイアリーのAtomPubと通じて、開発者ははてなダイアリーの日記を参照、投稿、編集、削除するようなオリジナルのアプリケーションを作成できます。
AtomPub について詳しくは http://www.ietf.org/rfc/rfc5023.txt (英語)などを参照してください。
本仕様解説中に現れるURIはURI Templateの記法に基づいて以下のように表記されます。
http://d.hatena.ne.jp/{はてなID}/atom/blog/{date}/{entry_id}
各変数の意味と書式は次のようになります。
HTTP の GET/POST/PUT/DELETE を特定のURIに対してリクエストし、そのリクエストに規定のXML文書を加えて送信することでインタフェースが用意している操作を行うことができます。
AtomPubには特定の操作の対象の集合を表す「コレクション」と個々の操作の対象を表す「メンバ」があります。コレクションとメンバはそれぞれにURIを持ち、そのURIに対して操作を行います。例えば、はてなダイアリーの日記エントリーのコレクションとメンバのURIは以下のようになります。
一部の操作はそのレスポンスとして規定のXML文書を返却します。また、下書きエントリーの公開操作を実現するためにAtomPubを拡張しています。
現時点でAPIがサポートしている操作は以下です。
以下、はてなダイアリーAtomPubの詳細を解説します。
はてなダイアリーAtomPubを利用するために、クライアントは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"
具体的な実装方法については、はてなフォトライフAtomAPIを参照してください。
はてなダイアリーAtomPubでは文字コードとしてUTF-8を利用します。リクエストXML、レスポンスXML共にUTF-8として扱ってください。
はてなダイアリーの他の場所では文字コードとしてEUC-JPを利用していることが多いので、まちがえないよう注意してください。
はてなダイアリーAtomPubで操作できるコレクションの一覧を含むサービス文書を取得できます。
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をGETすることで、日記エントリー一覧を取得できます。一度に20件のエントリーを取得できます。また、pageパラメータに数値を指定することで、20件目以降のエントリーを取得できます。
GET /{はてなID}/atom/blog GET /{はてなID}/atom/blog?page=2
指定ページに対応した Atom Feed 文書が返却されます。ここでは省略します。
コレクションURIに対してXML文書をPOSTすることで、日記エントリーを投稿できます。
リクエストXML文書に必要なパラメータは以下です。
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/{date}/{entry_id} <?xml version="1.0" encoding="utf-8"?> <entry xmlns="http://www.w3.org/2005/Atom"> <id>tag:d.hatena.ne.jp,2008:diary-はてなID-{date}-{entry_id}</id> <link rel="edit" href="http://d.hatena.ne.jp/{はてなID}/atom/blog/{date}/{entry_id}"/> <link rel="alternate" type="text/html" href="http://d.hatena.ne.jp/{はてなID}/{date}/{entry_id}"/> <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> <p> </p> </div> </content> </entry>
メンバURIをGETすることで、日記エントリーを取得できます。
GET /{はてなID}/atom/blog/{date}/{entry_id}
<?xml version="1.0" encoding="utf-8"?> <entry xmlns="http://www.w3.org/2005/Atom"> <id>tag:d.hatena.ne.jp,2008:diary-{はてなID}-{date}-{entry_id}</id> <link rel="edit" href="http://d.hatena.ne.jp/{はてなID}/atom/blog/{date}/{entry_id}"/> <link rel="alternate" type="text/html" href="http://d.hatena.ne.jp/{はてなID}/{date}/{entry_id}"/> <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> <p> </p> </div> </content> <hatena:syntax xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#"> 日記エントリー本文 - はてな - 記法</hatena:syntax> </entry>
メンバURIに対してXML文書をPUTすることで、日記エントリーを編集できます。投稿された日記エントリーの日時は投稿を行った日時になります。
リクエストXML文書に必要なパラメータは以下です。
PUT /{はてなID}/atom/blog/{date}/{entry_id} <?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}-{date}-{entry_id}</id> <link rel="edit" href="http://d.hatena.ne.jp/{はてなID}/atom/blog/{date}/{entry_id}"/> <link rel="alternate" type="text/html" href="http://d.hatena.ne.jp/{はてなID}/{date}/{entry_id}"/> <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> <p> </p> </div> </content> </entry>
メンバURIをDELETEすることで、日記エントリーを削除できます。
DELETE /{はてなID}/atom/blog/{date}/{entry_id}
HTTP/1.1 200 OK
はてなダイアリーの下書きを操作するためのコレクションです。下書きエントリーの投稿、取得、編集、削除、一覧の取得、および日記エントリーとしての公開を行うことができます。コレクションURI、およびメンバURIは以下になります。
下書きコレクションの操作は基本的にブログコレクションと同等なため詳しい説明は省略します。ただし、返却されるAtom Entryのcontent要素に含まれるのがはてな記法のみになっていることに注意してください。
はてなダイアリーAtomPubでは、AtomPubで規定されているapp:draft要素を使用しません。はてなダイアリーでは日記エントリと下書きエントリを別々に管理しています。そのため、日記エントリと下書きエントリを一つのコレクションとして扱い、app:draft要素によって下書きかどうかを区別するような構成は不自然になります。むしろ、下書きエントリを日記エントリとして公開するという操作を行う仕組みであるほうが自然であると考え、以下のような方法をとっています。
メンバURIに対してX-HATENA-PUBLISHヘッダを付与してPUTすることで、メンバURIで指定した下書きをもとに日記エントリーを投稿できます。投稿された日記エントリーの日時は投稿を行った日時になります。
PUT /{はてなID}/atom/draft/{entry_id} X-HATENA-PUBLISH: 1
実際のレスポンスの例はブログコレクションの日記エントリーの投稿を参照してください。
はてなダイアリーAtomPubに対して不正な操作を行った場合にエラーレスポンスが返却されます。各エラーレスポンスには次のような意味があります。
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 から 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 end private def set_common_info(req) req['X-Hatena-Publish'] = 1 if @hatena_publish super(req) end end end
エントリーの新規作成のサンプルコードは以下です。
auth = 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' % 'はてなID' collection_uri = service.workspace.collections[1].href entry = Atom::Entry.new( :title => 'My Entry Title', :updated => Time.now ) entry.content = <<EOF エントリー本文だよ EOF puts 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
*1:ヘッダに含める際にbase64エンコーディングする必要があります