Hatena Fotolife AtomAPI

はてな

Hatena Fotolife AtomAPI

はてなふぉとらいふあとむえーぴー

Notes

Changelog

What is AtomAPI?

The AtomAPI is an application level protocol for publishing and editing web resources. Developers can make their original applications which can post, refer, edit, delete photos using Hatena Fotolife's AtomAPI. Please refer to http://www.ietf.org/html.charters/atompub-charter.html for more detail of AtomAPI.

Hatena Fotolife's AtomAPI is an interface to manipulate Hatena Fotolife from original applications. Users can implements their applications without a HTML scraping using Hatena Fotolife's AtomAPI.

Summary of AtomAPI implementation on Hatena Fotolife.

Hatena Fotolife's Atom API implementation supports only the REST formats. Currently, this API does not support SOAP formats.

To execute operation, you need to HTTP GET/POST/PUT/DELET to specified URI with XML documents.

Some of operations return XML documents as a response.

Followings are current supported operations on API.

  • Post a new photo. (POST to PostURI)
  • Change title of a photo. (PUT to EditURI)
  • Delete a photo. (DELETE to EditURI)
  • Refer a photo. (GET to EditURI)
  • Get a list of recent posted photos. (GET to FeedURI)

Followings describe detailed information of Hatena Fotolife AtomAPI.

WSSE Authentication.

Authentication uses WSSE. All methods on Hatena Fotolife API require WSSE authentication. More documentation on WSSE authentications is linked from http://www-128.ibm.com/developerworks/webservices/library/ws-secure/. In this section, we explain WSSE authentication briefly.

WSSE is an authentication method which send authentication token using "X-WSSE" HTTP header. WSSE authentication includes username and password. Password was SHA1 encoded, so it is secure compared to basic autentication.

Sample X-WSSE HTTP header is as follows:

X-WSSE: UsernameToken Username="hatena", PasswordDigest="ZCNaK2jrXr4+zsCaYK/YLUxImZU=", Nonce="Uh95NQlviNpJQR1MmML+zq6pFxE=", Created="2005-01-18T03:20:15Z"
Username
The username that the user enters (in this case username at Hatena).
Nonce
A secure token generated anew for each HTTP request.
Created
The ISO-8601 timestamp marking when Nonce was created.
PasswordDigest
A SHA-1 digest of the Nonce, Created timestamp, and the password that the user supplies, base64-encoded.

All of endpoints on Hatena Fotolife require WSSE authentification.

Root Atom Endpoint

The root endpoint for Hatena Fotolife AtomAPI is as follows:

http://f.hatena.ne.jp/atom

To obtain a PostURI and FeedURI, send a GET request to the root endpoint.

Request

GET /atom

Response

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

PostURI is a endpoint to upload an photo to the Hatena Fotolife. This endpoint only supports POST method.

To upload a photo to Hatena Fotolife, send a POST request to the PostURI. Base64-encoded representation of the photo data must be included in the content of POST request. You can specify a folder to upload a photo in the optional element http://purl.org/dc/elements/1.1/subject, which should be the folder name on Hatena Fotolife. If the specified folder does not exist, new folder will be created.

Parameters for Request are as follows:

  • Set title of the photo to title element.
  • Set photo data to content element.
  • dc:subject element is foldername to upload.
    • If specified folder does not exist on Hatena Fotolife, new folder is created automatically.
  • Set upload tool name to generator element.
    • You can set sort setting for each uploader on Hatena Fotolife's setting.

If some operation has failed, Hatena Fotolife API returns status code which is different from valid response and error message as HTTP header.

Request

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>

Response

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

EditURI is a endpoint for following operations.

  • Refer specific photo entry's feed. (GET)
  • Edit photo (PUT)
  • Delete photo (DELETE)

If some operation has failed, Hatena Fotolife API returns status code which is different from valid response and error message as HTTP header.

Request

GET /atom/edit/XXXXXXXXXXXXXX

Response

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>

Request

PUT /atom/edit/XXXXXXXXXXXXXX

<entry xmlns="http://purl.org/atom/ns#">
  <title>My Photo</title>
</entry>

Replacement of specific photo entry is not supported on PUT for EditURI. Please delete and post new photo to the entry.

Response

200 OK

Request

DELETE /atom/edit/XXXXXXXXXXXXXX

Response

200 OK

FeedURI

FeedURI is an endopoint to get recent photo entries as ATOM feed. This endpoint only supports GET methods.

The amount of entries which is included in a feed, is set by user setting on Hatena Fotolife.

Request

GET /atom/feed

Response

Returns same results as Atom Feed on Hatena Fotolife. Details are abbreviated.

Implementation of WSSE authentification using Perl

Follwing is an example implementation of WSSE authentification.

#!/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;

This code generate X-WSSE header and pass Hatena Fotolife's AtomAPI endpoint authentification. After that this code send GET to root endpoint and retrieve PostURI and EditURI.

And if you use CPAN LWP::Authen::Wsse module, you don't need to write generation logic of X-WSSE header.

Following is a sample code. This code can send requests with authentification header.

my $ua = LWP::UserAgent->new;
$ua->credentials('f.hatena.ne.jp:80', '', 'username', 'password');

Post a photo using CPAN module XML::Atom::Client

XML::Atom::Client is a module to implement AtomAPI client. This module abstracts WSSE authentification and construction of XML document.

Below is a sample code to upload photos to Hatena Fotolife using XML::Atom::Cliet.


#!/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;

You can pass authentification by setting username/password method since XML::Atom::Client abstracts WSSE authentification.

To construct XML document, create XML::Atom::Entry instance and pass it to XML::Atom::Client instance.

To execute this script, type following command.

$ perl atompost.pl hatena hatena ./sample.jpg

You need to specify photo data at third argument. Base64 encoding is also abstracted by XML::Atom::Entry, programmers do not need to implement encoding.