はじめに
はじめまして。井上武
2007年後半はAtomPub
このように、
この連載では、
サンプルコードはこちらからダウンロードできます。
Catalyst::Controller::Atompub 開発の経緯
Catalyst::Controller::Atompubは、
最初は昨年7月末に開催されたAtomPubの接続実験のために開発されました。この時点ではまだ独立したモジュールではなく、
Catalystに詳しい中川さんにアドバイスをいただきながら開発を進め、
現在、
Catalystとは
Catalystは、
AtomPubは、
AtomPubとは
AtomPubは、
gihyo.
ここでは、
AtomPubのリソース
AtomPubはWeb上のリソースを扱うプロトコルです。まずはリソースから説明します。AtomPubでは、
![AtomPubのリソース AtomPub のリソース](/assets/images/dev/feature/01/atompub/0001/thumb/TH400_01-02.jpg)
メンバリソースがAtomエントリのときは
今回はエントリリソースについて説明し、
リソースの操作
コレクションとメンバはそれぞれのURIを持ちます。そのURIに対してクライアントがHTTPリクエストを送ると、
コレクションのURIにHTTP GETリクエストが送られると、
![コレクションからメンバ一覧を取得 コレクションからメンバ一覧を取得](/assets/images/dev/feature/01/atompub/0002/thumb/TH400_02-01.jpg)
![コレクションにメンバを追加 コレクションにメンバを追加](/assets/images/dev/feature/01/atompub/0002/thumb/TH400_02-03.jpg)
メンバのURIにHTTP GETリクエストが送られると、
![メンバを取得 メンバを取得](/assets/images/dev/feature/01/atompub/0002/thumb/TH400_02-02.jpg)
![メンバを更新 メンバを更新](/assets/images/dev/feature/01/atompub/0002/thumb/TH400_02-04.jpg)
![メンバを削除 メンバを削除](/assets/images/dev/feature/01/atompub/0002/thumb/TH400_02-05.jpg)
5つの操作を表にまとめます
URI | HTTPメソッド | 操作 | メソッド属性 |
コレクション | GET | メンバの列挙 | list |
コレクション | POST | メンバの追加 | create |
メンバ | GET | メンバの取得 | read |
メンバ | PUT | メンバの更新 | update |
メンバ | DELETE | メンバの削除 | delete |
このように、
Catalyst::Controller::Atompubの特徴
ここまで見てきたように、
ところが、
Catalyst::Controller::Atompubは、
Catalystのインストール
AtomPubサーバを実装する前に、
% sudo cpan -i Catalyst::Runtime Catalyst::Plugin::ConfigLoader \ Catalyst::Plugin::Static::Simple Catalyst::Model::DBIC::Schema \ DBIx::Class::Schema::Loader DBD::SQLite Catalyst::View::TT \ Catalyst::Controller::Atompub Catalyst::Action::RenderView
連載が進むにつれて他のモジュールを使うこともありますが、
準備が終わったら、
% catalyst.pl MyBlog % cd MyBlog/
モデルとテーブルの作成
Catalyst::Controller::Atompubでは、
テーブル作成
まず、
MyBlog % sqlite3 test.db sqlite> CREATE TABLE entries ( ...> id INTEGER PRIMARY KEY, ...> edited INTEGER, ...> uri TEXT UNIQUE, ...> xml BLOB ...> );
idはエントリの通し番号です。editedはエントリの最終更新日時です。UNIX time
モデルの作成
次に、
MyBlog % perl script/myblog_create.pl model DBIC DBIC::Schema MyBlog::Model::Schema dbi:SQLite:dbname=test.db
コマンドの引数は次の通りです。
引数 | 説明 |
model | 作成対象 |
DBIC | 作成するクラス名 |
DBIC::Schema | スーパークラス名 |
MyBlog::Model::Schema | スキーマ情報を扱うクラス名 |
dbi:SQLite:dbname=test. | データベースへの接続情報 |
コマンドを実行すると、
続いて、
package MyBlog::Model::Schema;
use base qw(DBIx::Class::Schema::Loader);
1;
コレクションコントローラの作成
コレクションを実装するコントローラを作成し、
ヘルパスクリプトを使ってコントローラのひな形を作成します。
MyBlog % ./script/myblog_create.pl controller EntryCollection Atompub::Collection
コマンドの引数は次の通りです。
引数 | 説明 |
controller | 作成対象 |
EntryCollection | 作成するクラス名 |
Atompub::Collection | スーパークラス名 |
コマンドを実行すると、
Catalyst::Controller::Atompubでは、
sub get_feed :Atompub(list) {
# メンバを列挙する...
}
それでは、
メンバの列挙 (List)
sub get_feed :Atompub(list) {
my($self, $c) = @_;
# フィード (XML::Atom::Feed) のひな型
my $feed = $self->collection_resource->body;
# entriesテーブルからエントリを取得する (更新日時の新しい順)
my $rs = $c->model('DBIC::Entries')
->search({}, { order_by => 'edited DESC' });
# フィードのひな形にエントリを追加する
while (my $entry_resource = $rs->next) {
my $entry = XML::Atom::Entry->new(\$entry_resource->xml);
$feed->add_entry($entry);
}
# 成功したらtrueを返す
return 1;
}
このメソッドが呼ばれる前に、
このメソッドでは、
メンバの追加(Create)
sub create_entry :Atompub(create) {
my($self, $c) = @_;
# スーパークラスが生成したURIと更新日時を取得する
my $uri = $self->entry_resource->uri;
my $edited = $self->edited->epoch; # (UNIX time 形式に変換)
# POSTされたエントリ本体を取得する (XML::Atom::Entry)
my $entry = $self->entry_resource->body;
# entriesテーブルにエントリとメタデータを格納する
$c->model('DBIC::Entries')->update_or_create({
edited => $edited,
uri => $uri,
xml => $entry->as_xml,
});
# 成功したらtrueを返す
return 1;
}
このメソッドが呼ばれる前に、
このメソッドでは、
ここで、
メンバの取得(Read)
sub get_entry :Atompub(read) {
my($self, $c) = @_;
# リクエストされたURI
my $uri = $c->req->uri;
# entriesテーブルからエントリを検索する
my $rs = $c->model('DBIC::Entries')->find({ uri => $uri });
# エントリリソースをセットする
my $entry = XML::Atom::Entry->new(\$rs->xml);
$self->entry_resource->body($entry);
# 成功したらtrueを返す
return 1;
}
このメソッドでは、
メンバの更新(Update)
sub update_entry :Atompub(update) {
my($self, $c) = @_;
# リクエストされた URI
my $uri = $c->req->uri;
# スーパークラスが生成した更新日時を取得する
my $edited = $self->edited->epoch; # (UNIX time 形式に変換)
# PUTされたエントリ本体を取得する (XML::Atom::Entry)
my $entry = $self->entry_resource->body;
# entriesテーブルからエントリを検索し、更新する
$c->model('DBIC::Entries')->search({ uri => $uri })->update({
edited => $edited,
xml => $entry->as_xml,
});
# 成功したらtrueを返す
return 1;
}
POSTの場合と同様に、
このメソッドでは、
メンバの削除(Delete)
sub delete_entry :Atompub(delete) {
my($self, $c) = @_;
# リクエストされたURI
my $uri = $c->req->uri;
# entriesテーブルからエントリを削除する
$c->model('DBIC::Entries')->search({ uri => $uri })->delete;
# 成功したらtrueを返す
return 1;
}
このメソッドでは、
以上でコレクションの作成が終わりました。
コレクションコントローラに関する補足
ここでは、
リソースを操作するときに、
Catalystの起動
ここまでで、
MyBlog % perl script/myblog_server.pl
ブラウザから http://
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>EntryCollection</title>
<updated>2008-01-13T18:22:44+09:00</updated>
<id>http://localhost:3000/entrycollection</id>
<link rel="self" href="http://localhost:3000/entrycollection"/>
</feed>
今回は、