本ドキュメントははてなフォトライフにおける AtomAPI 実装を解説するものです。主にはてなスタッフがその作成と更新を行っています。
Atomプロジェクトが定めるAtomAPI仕様 http://www.ietf.org/html.charters/atompub-charter.html (英語)は現時点でドラフト段階です。それに伴い本ドキュメントおよびはてなフォトライフの AtomAPI 実装は変更される可能性があります。
AtomAPI はウェブリソースを出版、編集するためのアプリケーション・プロトコル仕様です。はてなフォトライフのAtomAPIを利用することで、開発者ははてなフォトライフに写真を参照、投稿、編集、削除したりを行うオリジナルのアプリケーションを作成することができます。
AtomAPIについて詳しくは http://www.ietf.org/html.charters/atompub-charter.html (英語)などを参照してください。
はてなフォトライフAtomAPI はオリジナルのアプリケーションからはてなフォトライフを操作するためのインターフェースです。はてなフォトライフAtomAPIを利用することで、HTMLを解析してパラメーターを組み立てPOSTするといった、いわゆるHTMLスクレイピングのような手法を行うことなしに、専用のAPIインタフェースを使ってアプリケーションを実装することができます。
はてなフォトライフAtomAPIはRESTをサポートしています。現時点でSOAPはサポートしていません。
HTTP の GET/POST/PUT/DELETE を特定のURIに対して行い、そのリクエストに規定のXML文書を加えて送信することでインタフェースが用意している操作を行うことができます。また、一部の操作はそのレスポンスとして規定のXML文書を返却します。
現時点でAPIがサポートしている操作は以下です。
以下、はてなフォトライフAtomAPIの詳細を解説します。
AtomAPIの認証にはWSSE認証が利用されます。はてなフォトライフAtomAPIの利用には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エンドポイントURIにはWSSE認証が設定されています。
はてなフォトライフAtomAPIのルートAtomエンドポイントは以下になります。ルートAtomエンドポイントに対しGETリクエストを行うことで、PostURIとFeedURIを取得することができます。
GET /atom
HTTP/1.1 200 OK Content-Type: application/x.atom+xml <?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://purl.org/atom/ns#"> <link type="application/x.atom+xml" rel="service.post" href="http://f.hatena.ne.jp/atom/post" title="fotolife sample"> <link type="application/x.atom+xml" rel="service.feed" href="http://f.hatena.ne.jp/atom/feed" title="fotolife sample"> </feed>
PostURIははてなフォトライフへ写真を新規投稿するためのエンドポイントです。POSTメソッドのみをサポートしています。PostURIに対し規定のリクエスト用XML文書をPOSTすることで写真の投稿が可能です。写真データBase64エンコードしてリクエスト用XML文書に記述します。また、Dublin Coreモジュールのdc:subject要素を追加することにより、ファルダ名を指定してアップロードすることができます。
リクエスト用XML文書に記述することができるパラメータは以下です。
操作が何かしらの理由によって失敗した場合は、正常レスポンスとは異なるステータスコードと、それに合わせたエラーメッセージをHTTPヘッダとして返却します。
POST /atom/post <entry xmlns="http://purl.org/atom/ns#"> <title>Sample</title> <content mode="base64" type="image/jpeg">/9j/2wCEAAQDAwQDAw.../9n/AA==</content> </entry>
201 Created Content-Type: application/x.atom+xml Location: http://f.hatena.ne.jp/atom/edit/XXXXXXXXXXXXXX <?xml version="1.0" encoding="utf-8"?> <entry xmlns="http://purl.org/atom/ns#" xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#"> <title>Sample</title> <link rel="alternate" type="text/html" href="http://f.hatena.ne.jp/naoya/XXXXXXXXXXXXXX"/> <link rel="service.edit" type="application/x.atom+xml" href="http://f.hatena.ne.jp/atom/edit/XXXXXXXXXXXXXX" title="Sample"/> <issued>2005-01-14T17:01:29+09:00</issued> <author> <name>naoya</name> </author> <generator url="http://f.hatena.ne.jp/" version="1.0">Hatena::Fotolife</generator> <dc:subject xmlns:dc="http://purl.org/dc/elements/1.1/">YYYYYY</dc:subjetct> <id>tag:hatena.ne.jp,2005:fotolife-naoya-XXXXXXXXXXXXXX</id> <hatena:imageurl>http://f.hatena.ne.jp/images/fotolife/n/naoya/XXXXXXXX/XXXXXXXXXXXXXX.jpg</hatena:imageurl> <hatena:imageurlsmall>http://f.hatena.ne.jp/images/fotolife/n/naoya/XXXXXXXX/XXXXXXXXXXXXXX_m.gif</hatena:imageurlsmall> <hatena:syntax>f:id:naoya:XXXXXXXXXXXXXX:image</hatena:syntax> </entry>
EditURIははてなフォトライフへ投稿した
を行うためのエンドポイントです。操作が何かしらの理由によって失敗した場合は、正常レスポンスとは異なるステータスコードと、それに合わせたエラーメッセージをHTTPヘッダとして返却します。
GET /atom/edit/XXXXXXXXXXXXXX
200 OK Content-Type: application/x.atom+xml <?xml version="1.0" encoding="utf-8"?> <entry xmlns="http://purl.org/atom/ns#" xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#"> <title>Sample</title> <link rel="alternate" type="text/html" href="http://f.hatena.ne.jp/naoya/XXXXXXXXXXXXXX"/> <link rel="service.edit" type="application/x.atom+xml" href="http://f.hatena.ne.jp/atom/edit/XXXXXXXXXXXXXX" title="Sample"/> <issued>2005-01-14T17:01:29+09:00</issued> <author> <name>naoya</name> </author> <id>tag:hatena.ne.jp,2005:fotolife-naoya-XXXXXXXXXXXXXX</id> <hatena:imageurl>http://f.hatena.ne.jp/images/fotolife/n/naoya/XXXXXXXX/XXXXXXXXXXXXXX.jpg</hatena:imageurl> <hatena:imageurlsmall>http://f.hatena.ne.jp/images/fotolife/n/naoya/XXXXXXXX/XXXXXXXXXXXXXX_m.gif</hatena:imageurlsmall> <hatena:syntax>f:id:naoya:XXXXXXXXXXXXXX:image</hatena:syntax> </entry>
PUT /atom/edit/XXXXXXXXXXXXXX <entry xmlns="http://purl.org/atom/ns#"> <title>My Photo</title> </entry>
※特定の画像エントリの画像データの置換はEditURIへのPUTではサポートしていません。該当のエントリの削除+新規投稿で対応してください。
200 OK
DELETE /atom/edit/XXXXXXXXXXXXXX
200 OK
FeedURIは、投稿された写真のうち最近のエントリをAtomフィードで取得するためのエンドポイントです。GETメソッドのみをサポートしています。
フィードに含まれるエントリの件数は、はてなフォトライフでのユーザー設定によって決定されます。
GET /atom/feed
はてなフォトライフがフィードしているAtomフィードと同様の結果を返します。ここでは省略します。
WSSE認証をPerlで実装する場合は、例えば以下のようになります。
#!/usr/local/bin/perl use strict; use warnings; use DateTime; use Digest::SHA1 qw (sha1); use HTTP::Request; use MIME::Base64 qw (encode_base64); use LWP::UserAgent; my $username = shift or die "need username\n"; my $password = shift; my $nonce = sha1(sha1(time() . {} . rand() . $$)); my $now = DateTime->now->iso8601 . 'Z'; my $digest = encode_base64(sha1($nonce . $now . $password || ''), ''); my $credentials = sprintf(qq(UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"), $username, $digest, encode_base64($nonce, ''), $now); my $req = HTTP::Request->new(GET => 'http://f.hatena.ne.jp/atom'); $req->header( Accept => 'application/x.atom+xml, application/xml, text/xml, */*'); $req->header( 'X-WSSE' => $credentials ); print LWP::UserAgent->new->request($req)->as_string;
X-WSSE ヘッダを作成し、はてなフォトライフAtomAPIエンドポイントの認証を通過して、ルートエンドポイントにGETすることで PostURI、EditURI を取得しています。
また、CPANモジュールのLWP::Authen::Wsse を利用すると、X-WSSEヘッダを生成するロジックを書かなくても、
my $ua = LWP::UserAgent->new; $ua->credentials('f.hatena.ne.jp:80', '', 'username', 'password');
と LWP::UserAgent に命令するだけで、認証ヘッダを追加したリクエストを送信することができます。
CPANモジュールのXML::Atom::ClientはAtomAPIクライアントを実装するための、WSSE認証やリクエスト、レスポンスに必要なXML文書の組み立てなどを抽象化したモジュールです。
XML::Atom::Clientを用いて、はてなフォトライフに任意の画像をアップロードするサンプルコードは以下のようになります。
#!/usr/local/bin/perl use strict; use warnings; use FileHandle; use XML::Atom::Entry; use XML::Atom::Client; my $PostURI = 'http://f.hatena.ne.jp/atom/post'; my $username = shift or die "need username"; my $password = shift; my $api = XML::Atom::Client->new; $api->username($username); $api->password($password); my $file = shift; local $/; # slurp mode my $fh = FileHandle->new($file) or die "cannnot open $file: $!"; my $image = $fh->getline; my $entry = XML::Atom::Entry->new; $entry->content($image); $entry->content->type('image/jpeg'); $entry->title('Sample image for AtomAPI'); my $EditURI = $api->createEntry($PostURI, $entry) or die $api->errstr; print $EditURI;
XML::Atom::Client はWSSE認証を抽象化しているため、username/passwordメソッドでそれぞれをセットするだけで認証を通過できます。また、XML文書の組み立てはXML::Atom::Entryインスタンスを生成して行い、それを最後にXML::Atom::Clientインスタンスに渡せば完了です。
このスクリプトはコマンドラインから実行し、
$ perl atompost.pl hatena hatena ./sample.jpg
として第3引数に画像ファイルを指定します。画像データのBase64エンコードもXML::Atom::Entryが抽象化しているので、プログラマは特に気にする必要はありません。
*1:ヘッダに含める際にbase64エンコーディングする必要があります