Perlを中心とした技術系の話などをつらつら

2006年11月25日

SledgeでもRESTfulなアプリケーションを書きたい!

今日参加した第9回XML開発者の日の川村さんによる「Ruby on RailsにみるRESTfulアプリケーションの方向性」の話を聞いて、SledgeでもRESTfulなコードを簡単に書きたいと思いたち、ちょっとパッチを書いてみました。

 --- Sledge/Pages/Base.pm.orig   2006-11-25 00:40:59.000000000 +0900
 +++ Sledge/Pages/Base.pm        2006-11-25 09:27:50.000000000 +0900
 @@ -8,6 +8,9 @@
  use strict;
  use base qw(Class::Accessor Class::Data::Inheritable);
 
 +use vars qw($MethodQueryKey);
 +$MethodQueryKey  = '_method';
 +
  __PACKAGE__->mk_accessors(
      'r',                       # Apache::Request or Sledge::Request::CGI
      'session',                 # Sledge::Session
 @@ -81,10 +84,16 @@
      eval {
         $self->init_dispatch($page);
         $self->invoke_hook('BEFORE_DISPATCH') unless $self->finished;
 -       if ($self->is_post_request && ! $self->finished) {
 +       if ( $self->is_put_request && ! $self->finished) {
 +           my $putmeth = 'put_dispatch_' . $page;
 +           $self->$putmeth() if $self->can($putmeth);
 +       } elsif ( $self->is_delete_request && ! $self->finished) {
 +           my $deletemeth = 'delete_dispatch_' . $page;
 +           $self->$deletemeth() if $self->can($deletemeth);
 +       } elsif ($self->is_post_request && ! $self->finished) {
             my $postmeth = 'post_dispatch_' . $page;
             $self->$postmeth() if $self->can($postmeth);
 -       }
 +    }
         unless ($self->finished) {
             my $method = 'dispatch_' . $page;
             $self->$method();
 @@ -188,6 +197,16 @@
      return $self->r->method eq 'POST';
  }
 
 +sub is_put_request {
 +    my $self = shift;
 +    return ($self->r->method eq 'PUT' || ($self->r->method eq 'POST' &&  lc($self->r->param($MethodQueryKey)) eq 'put'));
 +}
 +
 +sub is_delete_request {
 +    my $self = shift;
 +    return ($self->r->method eq 'DELETE' || ($self->r->method eq 'POST' && lc($self->r->param($MethodQueryKey)) eq 'delete'));
 +}
 +
  sub make_content {
      my $self = shift;
      # template output, then fillin forms

これを使って書いたPagesクラスのサンプルはこんな感じです。

package MyProj::Pages::Items;
use strict;
use base qw(MyPfoj::Pages);
sub dispatch_index {
    my $self = shift;
    my $item_id = int $self->r->param('id');
    if ( $item_id ){
        # アイテム単体を返すコードを記述
    } else {
        # アイテムリストを返すコードを記述
    }
}
sub post_dispatch_index {
    my $self = shift;
    # アイテムを追加するコードを記述
}
sub put_dispatch_index {
    my $self = shift;
    # アイテムを更新するコードを記述
}
sub delete_dispatch_index {
    my $self = shift;
    # アイテムを削除するコードを記述
}

MyProj::Pages::Itemsクラスがアイテムをあらわすリソースに対応していて、

各メソッドにあわせて、CRUDの操作を実行するという風に書けてすっきりする気がします。

ブラウザからはPUT,DELETEリクエストはできないので、_method=putまたはdeleteとクエリパラメータを使うことで代用しています。

こんなのいかがでしょうか?

Technorati TAGTechnorati TAG , ,

Posted by horiuchi at 2006年11月25日 00:48

Continuing the discussion...

このエントリーのトラックバックURL:
http://hori-uchi.com/mt/trackback/451

Comments

head_dispatch_* も欲しいです!

Posted by jiro at 2006年11月25日 09:55

jiroさんこんにちは。
HEADリクエストのレスポンスヘッダはGETリクエストと同一でないといけないらしいので、head_dispatch_**を定義して独自に処理させるよりは、outpu_contentあたりに手をいれて、HEADリクエストだったら、コンテントを返さないって風にしたほうがいいような気がしますが、どうでしょう?

$self->print($content) unless $self->is_head_request;

みたいな。

Posted by hori-uchi at 2006年11月26日 02:50

Post a comment




Remember personal info?