たけまる / Catalyst::Controller::Atompub - URI の命名規則
2007-10-22
_
Catalyst::Controller::Atompub - URI の命名規則 [perl][atompub]



間があいてしまいましたが,Atompub モジュールの使い方シリーズです.Catalyst::Controller::Atompub は Catalyst の拡張モジュールで,
AtomPub (Atom Publishing Protocol) サーバを簡単に実装することがで
きます.
# クライアントは Atompub モジュール [2007-08-12-1] にあります.
さて,AtomPub サーバの基本的な機能である "リソースの CRUD (作成,
取得,更新,削除)" については [2007-09-13-1] と [2007-09-27-1] で
説明しました.今回は,リソース URI の変更方法について説明します.
"REST" というアーキテクチャスタイルを知っている人は多いかと思いま
す.REST は URI でリソースを表し,GET, POST などの HTTP メソッドで
リソースを操作します.AtomPub は REST を実装したプロトコルのひとつ
です.REST では URI が重要な役割を果たします.
# REST の詳しい解説は yohei-y:weblog: REST 入門 にあります.
■ Default URIs
デフォルトでは,C::C::Atompub::Collection モジュールが自動的にリソー
ス URI を決定します.命名規則は次のようになっています.
- URI の前半部分は Collection URI と同じ - HTTP Request に Slug ヘッダがあれば,それを基にリソース名を作成 - 空白とドット (.) はアンダースコア (_) に変更 - 大文字は小文字に変換 - URI に使えない文字は Percent Encode - Slug がなければ,日時から自動生成 - HTTP Request の Content-Type を参考に,一般的な拡張子を付与
たとえば,Slug が "Entry 1" であるような Atom Entry が,
http://example.com/collection という Collection に POST されたとし
ます.
POST /collection HTTP/1.1 Host: example.com ... 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>
この場合のリソース URI は http://example.com/colleciton/entry_1.atom
となります.AtomPub 仕様に従い Slug の値が Percent Encode されてい
ますが,"Entry 1" に戻してから処理を行います.
また,Slug のない GIF 画像が POST されたときの URI は,
http://example.com/colleciton/20071022-123456-123456.gif のように
なります.リソース名の部分は,"年月日 - 時分秒 - マイクロ秒" です.
この命名規則は AtomPub としては標準的だと思いますが,重複チェック
していないなどの問題点もあります.
■ Changing URIs of Entry Resoures
命名規則を変更するには,C::C::Atompub::Collection のサブクラスで
make_edit_uri メソッドを override します.
Entry リソースを扱う Collection で,URI の重複チェックを行うように
変更してみます.URI は "entries" テーブルの uri カラムに格納されて
いるとします.
package MyAtom::Controller::MyCollection;
use POSIX qw( strftime );
use Time::HiRes qw( gettimeofday );
use base qw( Catalyst::Controller::Atompub::Collection );
sub make_edit_uri {
my ( $self, $c, @args ) = @_;
# 親クラスの make_edit_uri を呼び出す
my $uri = $self->SUPER::make_edit_uri( $c, @args );
# URI が存在しなければ,そのまま返す
return $uri unless $c->model('Entries')->find( { uri => $uri } );
# URI が重複するときは,日時を拡張子の前に挿入する
my ( $sec, $usec ) = gettimeofday;
my $dt = strftime '%Y%m%d-%H%M%S', localtime( $sec );
$usec = sprintf '%06d', $usec;
$uri =~ s{(\.[^./?]+)$}{-$dt-$usec$1};
return $uri;
}
親クラスが決定した URI を検索し,存在するときには日時を追加して重
複を回避します.たとえば,http://example.com/colleciton/entry_1.atom
という URI がすでに存在しているといれば,http://example.com/colleciton/entry_1-20071022-123456-123456.atom
のように日時を追加します.
■ Changing URIs of Media Resources and Media Link Entries
Media リソースを扱う Collection では,Media リソースだけでなく
Media Link Entry の URI も決定しなければなりません.この場合,
make_edit_uri はふたつの URI を返します.ひとつめが Media Link
Entry, ふたつめが Media リソースです.
先ほどと同様に,URI の重複を回避するように修正してみます.Media
Link Entry と Media リソースの URI は,それぞれ "entry_uri",
"media_uri" というカラムに格納されているとします.
package MyAtom::Controller::MyCollection;
use POSIX qw( strftime );
use Time::HiRes qw( gettimeofday );
use base qw( Catalyst::Controller::Atompub::Collection );
sub make_edit_uri {
my ( $self, $c, @args ) = @_;
# 親クラスの make_edit_uri を呼び出す
my ( $entry_uri, $media_uri ) = $self->SUPER::make_edit_uri( $c, @args );
# URI が存在しなければ,そのまま返す
return ( $entry_uri, $media_uri )
unless $c->model('Entries')->find( {
'-or' => [ { entry_uri => $entry_uri }, { media_uri => $media_uri } ]
} );
# URI が重複するときは,日時を拡張子の前に挿入する
my ( $sec, $usec ) = gettimeofday;
my $dt = strftime '%Y%m%d-%H%M%S', localtime( $sec );
$usec = sprintf '%06d', $usec;
$_ =~ s{(\.[^./?]+)$}{-$dt-$usec$1} for ( $entry_uri, $media_uri );
return ( $entry_uri, $media_uri );
}
■ Changing URIs of //content/@src
AtomPub では,Media リソースを表す URI がふたつあります.ひとつは,
link 要素で,もうひとつは content 要素です.
<entry> <link rel="edit-media" href="http://example.com/collection/foo.gif"/> <content src="http://example.com/collection/foo.gif"/> ... </entry>
C::C::Atompub::Collection は,デフォルトでは,両者に同じ URI を割
り当てます.ここまではこのふたつを区別せずに説明しました.
しかし,CRUD 操作に対してはリソース本体を返し,通常のアクセスに対
してはキャッシュを返したいときがあります.このような理由で,別々の URI を用意したいこと
があります.
そのときには,POST あるいは PUT されたリソースを格納する前に,
//content/@src をキャッシュ用 URI に変更してください.
