PerlでAtomPubサーバを作ろう!

第3回 AtomPubをより効果的に ─ 認証・キャッシュなど

この記事を読むのに必要な時間:およそ 6 分

メンバリソースのURIの指定

メンバリソースURI(Edit URI)は,リソースが追加されたときにAtomPubサーバによって決定されます。ここでは,デフォルトURIの変更方法を説明します。

デフォルトURI

デフォルトでは,次のようにしてメンバリソースURIが決定されます。

  1. まず,メンバリソースURIは,コレクションのURIとメンバリソース名,拡張子を連結したものです。
  2. メンバリソース名は次のように決定されます。HTTPリクエストにSlugヘッダがあれば,それをリソース名とします。このとき,空白とドット"."をアンダースコア"_"に変更します。大文字を小文字に変換します。URIに使えない文字はPercent Encodeします。Slugがなければ,"年月日-時分秒-マイクロ秒"をリソース名とします。
  3. 拡張子には,HTTPリクエストのContent-Typeに対応する一般的な拡張子を選びます(MIME::Typesモジュールを使っています)⁠拡張子が不明であれば".bin"とします。

次のHTTPリクエストを例に説明します。

POST /entrycollection HTTP/1.1
Host: localhost:3000
Content-Type: application/atom+xml;type=entry
Slug: Entry%201

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  ...
</entry>

Slugヘッダのスペース(%20)を"_"に置換し,大文字を小文字に変換すると,リソース名は"entry_1"となります。また,Content-TypeはAtomエントリを表していますので,拡張子は".atom"になります。最終的に,このリソースのURIはhttp://localhost:3000/colleciton/entry_1.atomとなります。

URIの変更

メンバリソース名と拡張子は自由に変更することができます。たとえば,Ruby on RailsのようにデータベースのレコードIDをリソース名にすることもできます。

URIの変更方法を説明する前に,デフォルト実装の問題点を説明します。デフォルトでは,同じSlugを持つリクエストに対して同じURIが生成されるます。このとき,新しいリソースが作られずに既存リソースが上書きされます(あるいは,データベースのUNIQUE制約違反でエラーとなります)⁠

このため,URI重複チェックの観点からもデフォルト実装を変更してください。メンバリソースのURIを変更するには,コレクションコントローラでmake_edit_uriメソッドをオーバライドします。

第1回で作成したエントリコレクションにmake_edit_uriを実装し,重複URIをチェックしてみます。

make_edit_uri(lib/MyBlog/Controller/EntriesCollection.pm)

use Time::HiRes qw(gettimeofday);
sub make_edit_uri {
    my($self, $c, @args) = @_;

    # スーパークラスのmake_edit_uriを呼び出す
    my $uri = $self->SUPER::make_edit_uri($c, @args);

    # URI がすでに存在するときは,拡張子の前にUNIX timeを挿入する
    if ($c->model('DBIC::Entries')->find({ uri => $uri })) {
        my $t = join '', gettimeofday;
        $uri =~ s{(\.[^.]+)$}{-$t$1};
    }

    # 空のリソースを作成し,URIを予約する
    $c->model('DBIC::Entries')->create({ uri => $uri });

    return $uri;
}

URIがすでに存在するときは,リソース名の後ろにUNIX time(マイクロ秒)を追加します。たとえば,foo.atomがすでに存在するときは,foo-1200118461123456.atomのように変更されます。

このように,make_edit_uriでURIを予約し,この後で呼ばれるメンバ追加メソッドでエントリ本体や更新日時を格納します。

メディアリソースを扱うエントリでは,メディアリンクエントリのURIに加えて,メディアリソースのURIを返します。

make_edit_uri(lib/MyBlog/Controller/MediaCollection.pm)

use Time::HiRes qw(gettimeofday);
sub make_edit_uri {
    my($self, $c, @args) = @_;

    # スーパークラスの make_edit_uri を呼び出す
    my($entry_uri, $media_uri)
        = $self->SUPER::make_edit_uri($c, @args);

    # 省略...

    return ($entry_uri, $media_uri);
}

著者プロフィール

井上武(いのうえたける)

NTTに入社後,未来ねっと研究所でマルチキャストやモバイルIPなどのネットワーク技術の研究開発に取り組んでいたが,最近はWebアーキテクチャに関する仕事をしている。

URLhttp://teahut.sakura.ne.jp/