Catalyst::Controller::Atompubのdispatch、Slugヘッダとか
Atompubの勉強始めました。
Catalyst::Controller::Atompubについて
こちらはid:teahut*1さん自身がPerl(Catalyst)でAtompubサーバーを作る解説記事を書かれていますので、そちらを見ると大体分かると思います。
で今の所、分かった事とか困ってる事とか書いてみる事にします。
URLが基本的にpackage名で固定されてしまう。
例えば、コレクションFeedを取得したい場合はコレクションリソースURIに対してGETするんですけど、そのCatalystアクションの書き方は、
sub get_feed :Atompub(list) { # implements }
みたいに書くんですが、これが仮にpackage MyApp::Foo::Collectionだとすると/foo/collectionに固定されてしまいます。
と言うのもCatalyst::Controller::Atompub::Collectionにて、
- create_action()にてAtompub(xxx)みたいなattributeがある場合はxxxに応じたhandlerとしてCODEREFを保持
- do_xxx(list, read, create, update, delete)を生成。この際、実行される実体は先ほど保持したCODEREF
- dispatchは基本的にdefault, edit_uriで行い、ここがURIが決めうちになる原因となっている。それぞれHTTP Methodに応じて適切な実体(do_xxx)を呼び出すようになっている
なので、自前のURIとして例えば、/foo/
力技とは、大体こんな感じ。
まず前提としてコレクションリソースURIにアクセスしたのかエントリリソースURIにアクセスしたかで、起動するメソッドが違う
- コレクションURI - default()
- GET, HEAD - _list()
- POST - _create()
- リソースURI - edit_uri()
- GET, HEAD - read()
- POST - _create()
- PUT - _update()
- DELETE - _delete()
で、default, edit_uriのdispatchが固定されてるんだから上書きしちゃえば良い。
sub default :Regex('^foo/(\w+)/collection') { my ($self, $c) = @_; $self->NEXT::default($c); } sub edit_uri: Regex('^foo/(\w[\w_-]+\w)/collection/([^-?&#][^?&#]*)') { my ($self, $c) = @_; $self->NEXT::edit_uri($c); }
そして、その後はdo_xxxを直接実装しちゃうのがいいのかなーと思います。
多分この辺りはたけまるさんやid:ikasam_aが適切な補足をしてくれると思います。
たけまるさんの指摘を元に$c->NEXT::xxxを$self->NEXT::xxxに修正しました。(2008-03-11T23:11:41+09:00)
ところで、
なお,ZIGOROu さんの例では,default メソッドを先に定義していますが, 探索順の関係から edit_uri を先にしてください
これってどういう事でしょう。ちょっと僕には分からなかったです。
追記 (2008-03-11T20:05:55+09:00)
id:ikasam_aが反応してくれたです。なるほどChainedアクションですか。
先の例だと、
sub user: Chained PathPart('foo') CaptureArgs(1) { my ($self, $c) = @_; } sub default: Chained('user') PathPart('collection') { my ($self, $c) = @_; } sub edit_uri: Chained('user') PathPart('collection') Args(1) { my ($self, $c) = @_; }
みたいな感じかな。
Catalyst::Controller::Resourcesも期待ageですね。
割り当てられるエントリリソースURIについて
この辺りはCatalyst::Controller::Atompub::Collectionのmake_edit_uri()にて実装されています。ソース見た方が早いので拝借。コメントは僕が勝手につけました。
sub make_edit_uri { my ( $self, $c, @args ) = @_; # XML::Atom::Feedオブジェクト my $collection_uri = $self->info->get( $c, $self )->href; my $basename; if ( my $slug = $c->req->slug ) { # Slugヘッダがある場合 my $slug = uri_unescape $slug; $slug =~ s/^\s+//; $slug =~ s/\s+$//; $slug =~ s/[.\s]+/_/; $basename = uri_escape lc $slug; } else { # Slugヘッダが無い場合 my ( $sec, $usec ) = gettimeofday; $basename = join '-', strftime( '%Y%m%d-%H%M%S', localtime($sec) ), sprintf( '%06d', $usec ); } my @media_types = map { media_type($_) } ( 'entry', @args ); my @uris; for my $media_type (@media_types) { my $ext = $media_type->extension || 'bin'; my $name = join '.', $basename, $ext; push @uris, join '/', $collection_uri, $name; } return wantarray ? @uris : $uris[0]; }
って訳でSlugヘッダがあるか無いかで命名規則が違う実装みたいです。
この辺りはRFC 5023 Atom Publishing Protocol 日本語訳 - Slugヘッダを見ると良く分かります。
Slug は HTTP エンティティヘッダであり、コレクションに POST が行われるときのこのヘッダの存在は、これから作成されるエントリないしメディアリソースを参照するために通常使用される URI の一部としてそのヘッダの値を使ってほしい、というクライアントの要求を示す。 新しく作成されたリソースのメンバ URI を作るとき、サーバは Slug ヘッダの値を使ってもよい(MAY)。たとえば、最後の URI セグメントにその値の中の単語の一部、あるいはすべてを使う。また、atom:id を作成するとき、あるいはメディアリンクエントリのタイトルとしてその値を使ってもよい(MAY)(9.6 節参照)。 サーバは Slug エンティティヘッダを無視することを選択してもよい(MAY)。サーバはそれを使う前に、ヘッダの値を変えるかもしれない(MAY)。たとえば、サーバはある文字を取り除くか、あるいは強調されていない文字を強調された文字に置き換えるか、あるいは下線をスペースで置き換えるかもしれない。
なので、Slugヘッダがあった場合は新しいエントリないしはメディアリソースのURIの一部として使用しても構わないと。
Atompub::Clientを使ってcreateEntryする場合は、
#!/usr/bin/perl use strict; use warnings; use XML::Atom::Entry; use Atompub::Client; sub create_entry { my ($title, $content) = @_; my $entry = XML::Atom::Entry->new; $entry->title($title); $entry->content($content); return $entry; } sub create { my ($collection_uri, $title, $content) = @_; my $client = Atompub::Client->new; return $client->createEntry( $collection_uri, create_entry($title, $content), $title ### ここがSlugヘッダの値になる ); } print create(@ARGV);
みたいなソースになる。
参考
- Web APIの次世代標準プロトコル「Atom Publishing Protocol」:特集|gihyo.jp … 技術評論社 - 分かりやすかったです。お勧め
- PerlでAtomPubサーバを作ろう!:特集|gihyo.jp … 技術評論社 - これは完全に写経してみたです
- http://www.amazon.co.jp/gp/redirect.html%3FASIN=4873113539%26tag=zigorou-22%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/4873113539%253FSubscriptionId=0G91FPYVW6ZGWBH4Y9G2 - この本は今読んでる所。
*1:たけまるさん