Plackでの500ページ表示

Bloged at : 2011-04-10 10:03:05

Plackを利用して、エラーページ(500) を表示する際には、Plack::Middleware::ErrorDocument を利用すればよい。ただし、このミドルウエアーは正常なデータレスポンスを500のコード等で返した際にのみ実行されるので、アプリケーション側で例外的なエラーが発生した場合には拾ってくれない。そういったケースの場合は、Plack::Middleware::HTTPExceptions と併用して利用すれば、例外エラーを正常な500コードのレスポンスに変換してくれるのでうまくいく。

  builder {
      enable "ErrorDocument",
          500 => '/uri/errors/500.html', 404 => '/uri/errors/404.html',
          subrequest => 1;
      enable "HTTPExceptions";
      $app;
  };

この際に気をつけなければならないのは順番で、HTTPExceptionsを $appに近い側で呼ばなければならない。
  • カテゴリ:
  • Tech

エラー標準化&ロジック共有化モジュールAplon

Bloged at : 2011-02-12 22:09:27



目的


  • エラー処理の標準化を行う
  • ロジックを共有しやすいようにする

概要


Webのコントローラに直接ロジックを書くと、使い回しがしづらい&Web依存(リクエスト/レスポンス等処理)が発生してしまうという問題の対応として、ロジック周りを外に出すという設計が一般的に行われます。Aplonはこのロジック部分の実装の標準化を行いつつ、実装の手助けを行い、また、作成したロジックを再>利用することを可能にします。

ソース


https://github.com/tomyhero/p5-Aplon/

チュウトリアル

基本

ロジック関数を作る

ユーザIDを渡すとユーザのデータが取得できる関数を試しに作ってみます。
package Aplon::Model::User;
use Mouse;
extends 'Aplon';

sub lookup {
 my $self = shift;
 my $id  = shift;
  if($id =~ /^[0-9]+$/ ){
      if($self->aplon_user('ADMIN_USER') ){
          return {
             name => 'tomohiro',
             password => '1111',
          };
      }else {
          return {
             name => 'tomohiro',
          };
     }
  }
  else {
      $self->abort_with('not_found');
  }

}
__PACKAGE__->meta->make_immutable();

no Mouse;

1;

ロジック関数を実行する
 my $model = Aplon::Model::User->new;

 eval {
   my $user = $model->lookup( 32 );
 };

 if( my $error_obj = $@){
   # エラー処理。
   print Dumper $error_obj->error_keys;
 }

利用ユーザで処理を変更する


aplon_user*1で利用ユーザを変更することにより、たとえばadminページではstatus = 0のデータを取得できる等の切り分けを簡単に行うことができます。

 my $model = Aplon::Model::User->new({ aplon_user => 'ADMIN_USER' });

 eval {
   my $user = $model->lookup( 32 ); # passwordも取得できる
 };

 if( my $error_obj = $@){
   # エラー処理
   print Dumper $error_obj->error_keys;
 };

Data::FormValidatorを利用する

Validateモジュール作成(Aplon::Validator::Data::Form::Validator)


Aplon::Validator::Data::Form::Validatorを利用することにより、簡単に Data::Form::Validatorと連動することができます。Aplon::Validator::Data::Form::Validatorだけではconstraintsの設定がありませんので、以下のように拡張する必要があります。

package MyApp::Validator::DFV;
use Mouse::Role;
with 'Aplon::Validator::Data::Form::Validator';
use Data::FormValidator::Constraints qw(:closures);
sub DFV_constraint_methods {
    my $self = shift;
    return +{
        status => qr/^[01]$/,
        name   => [
            FV_max_length(10),
            qr/^[a-zA-Z0-9_]+$/,
            qr/^[a-zA-Z_]+$/, # multi invalid test
        ],
    }
}
sub DFV_constraint_method_regexp_map {
    my $self = shift;
    return +{
        qr/_id$/ => qr/^[0-9]+$/,
    }
}

1;
Modelモジュールで利用する

package MyApp::Model::User;
use Mouse;
extends 'Aplon';
with 'MyApp::Validator::DFV';

sub profiles {
    my $self = shift;
    return {
        get_name => {
            required => [qw/name/],
            optional => [qw/status/],
        }
    }
}

sub get_name {
    my $self = shift;
    my $args = shift;
    my $results = $self->assert_with($args);
    if($results->valid->{status}){
        return $results->valid->{name};
    }
    else {
        $self->abort_with($results,'not_found');
     }

}

__PACKAGE__->meta->make_immutable();

no Mouse;
1;

実行する

 eval {
  $model->get_name({ name => 'tomohiro.teranishi', status => 1 })
 };

if(my $error_obj = $@ ){
 # do error thing with $error_obj
}


同じ用な感じでAplon::Validator::FormValidator::LazyWay を利用することができます。さらに詳しくは https://github.com/tomyhero/p5-Aplon/tree/master/t 配下を見ていただければと。

エラーオブジェクトについて


特に複雑なものではなく、以下の情報がエラーがあった際に格納される感じです。
エラーメッセージ等は、error_keysから作成することができると思います。例えばこんな感じです。

package Aplon::Error;
use Mouse;

has 'code' => ( is => 'rw' , default => 'ERROR' );
has 'missing' => (is => 'rw', default => sub { [] } );
has 'invalid' => (is => 'rw', default => sub { {} } );
has 'valid' => (is => 'rw', default => sub { {} } );
has 'custom_invalid' => (is => 'rw', default => sub { [] } );
has 'error_keys' => ( is => 'rw' , default => sub { [] } );

__PACKAGE__->meta->make_immutable();

no Mouse;

1;

CRUDを実装する


実装してないです。lookup/search/remove/add/update 等をMixInするだけで利用できる感じの実装とかです。
全員に汎用的なのを作るのは難しいので、Project毎や、ORM毎等に作るかたちになります。

汎用的なロジックを作る


作ってないんですが、Aplon::Model::Twitter::OAuth, Aplon::Model::OpenID 等認証部分が特に汎用的に作りやすいきがします。
  • カテゴリ:
  • Tech

Appホームディレクトリ取得モジュールApp::Home

Bloged at : 2011-01-24 23:01:52

アプリケーション作成時には、システムの配備情報を扱うために、アプリケーションホームディレクトリを取得する必要が、必ずでてきます。そのソースをフレームワークを作る毎に作成するのがめんどくさいので App::Home というのをさっき暇つぶしに作成し,githubに上げました。もしかしたらすでにそういうモジュールがあるのかもしれません。

利用方法


まず継承する

package MyApp::Home;
use parent 'App::Home';
1;


利用する。get()メソッドしか使い道はないです。Path::Class::Dir のobjectを返します。また、シングルトンで実装されているので、一度呼べば後速いですし、同じ値を返すことを約束しています。

my $home = MyApp::Home->get();

Home発見ロジック


Homeディレクトリ取得ロジックは、ikebeさんの作成したPicklesのPickles::Configのhomeを見つけるロジックがいい感じなので、そこからソースを盗んで実装しています。環境変数を探して見つからなければ、アプリケーション::Homeライブラリの配備位置から取得する感じになっています。

あとがき


homeディレクトリを見つけるという単純なことなのですが、フレームワークを作成する際には必ず必要になる重要な機能です。お家は大切なのでたまには親孝行しようということでした。
  • カテゴリ:
  • Tech
1 2 3 4 5