Plackでの500ページ表示
Bloged at : 2011-04-10 10:03:05
Plackを利用して、エラーページ(500) を表示する際には、Plack::Middleware::ErrorDocument を利用すればよい。ただし、このミドルウエアーは正常なデータレスポンスを500のコード等で返した際にのみ実行されるので、アプリケーション側で例外的なエラーが発生した場合には拾ってくれない。そういったケースの場合は、Plack::Middleware::HTTPExceptions と併用して利用すれば、例外エラーを正常な500コードのレスポンスに変換してくれるのでうまくいく。
この際に気をつけなければならないのは順番で、HTTPExceptionsを $appに近い側で呼ばなければならない。
builder { enable "ErrorDocument", 500 => '/uri/errors/500.html', 404 => '/uri/errors/404.html', subrequest => 1; enable "HTTPExceptions"; $app; };
この際に気をつけなければならないのは順番で、HTTPExceptionsを $appに近い側で呼ばなければならない。
エラー標準化&ロジック共有化モジュールAplon
Bloged at : 2011-02-12 22:09:27
目的
- エラー処理の標準化を行う
- ロジックを共有しやすいようにする
概要
Webのコントローラに直接ロジックを書くと、使い回しがしづらい&Web依存(リクエスト/レスポンス等処理)が発生してしまうという問題の対応として、ロジック周りを外に出すという設計が一般的に行われます。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 等認証部分が特に汎用的に作りやすいきがします。
Appホームディレクトリ取得モジュールApp::Home
Bloged at : 2011-01-24 23:01:52
アプリケーション作成時には、システムの配備情報を扱うために、アプリケーションホームディレクトリを取得する必要が、必ずでてきます。そのソースをフレームワークを作る毎に作成するのがめんどくさいので App::Home というのをさっき暇つぶしに作成し,githubに上げました。もしかしたらすでにそういうモジュールがあるのかもしれません。
まず継承する
利用する。get()メソッドしか使い道はないです。Path::Class::Dir のobjectを返します。また、シングルトンで実装されているので、一度呼べば後速いですし、同じ値を返すことを約束しています。
Homeディレクトリ取得ロジックは、ikebeさんの作成したPicklesのPickles::Configのhomeを見つけるロジックがいい感じなので、そこからソースを盗んで実装しています。環境変数を探して見つからなければ、アプリケーション::Homeライブラリの配備位置から取得する感じになっています。
homeディレクトリを見つけるという単純なことなのですが、フレームワークを作成する際には必ず必要になる重要な機能です。お家は大切なのでたまには親孝行しようということでした。
利用方法
まず継承する
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ディレクトリを見つけるという単純なことなのですが、フレームワークを作成する際には必ず必要になる重要な機能です。お家は大切なのでたまには親孝行しようということでした。