@nqounet です。
前回は、アクション名から自動でハンドラーを生成する仕組みを作りました。
今回は、URLパターンでハンドラーを振り分ける機能を追加します。
問題:単純な名前だけでは足りない これまではlistやformのような単純な名前でハンドラーを選んでいました。しかし、実際のWebアプリケーションでは、URLパターンで振り分けたい場面が多くあります。
例えば:
/posts → 投稿一覧/posts/123 → 投稿ID 123の詳細/posts/new → 新規投稿フォームURLの形式を見て、適切なハンドラーを選ぶ仕組みが必要です。
解決策:正規表現でURLパターンをマッチング URLパターンと対応するハンドラーを登録し、正規表現でマッチングする仕組みを作ります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package Router {
use Moo ;
has routes => (
is => 'ro' ,
default => sub { [] },
);
sub add_route {
my ( $self , $pattern , $handler ) = @_ ;
push @ { $self -> routes }, {
pattern => $pattern ,
handler => $handler ,
};
}
sub match {
my ( $self , $path ) = @_ ;
for my $route ( @ { $self -> routes }) {
my $pattern = $route -> { pattern };
if ( $path =~ /^$pattern$/ ) {
return $route -> { handler };
}
}
return undef ; # マッチしなかった
}
};
add_routeでURLパターン(正規表現)とハンドラーを登録し、matchでパスに一致するハンドラーを探します。
使ってみよう 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ルーターを作成
my $router = Router -> new ;
# ルートを登録
$router -> add_route ( '/posts' , ListHandler -> new );
$router -> add_route ( '/posts/new' , FormHandler -> new );
$router -> add_route ( '/posts/(\d+)' , DetailHandler -> new );
# マッチングしてハンドラーを取得
my $handler = $router -> match ( '/posts' ); # ListHandler
$handler -> run if $handler ;
$handler = $router -> match ( '/posts/123' ); # DetailHandler
$handler -> run if $handler ;
$handler = $router -> match ( '/unknown' ); # undef(マッチしない)
warn "Not Found" unless $handler ;
URLの形式に応じて、適切なハンドラーが選ばれるようになりました。
flowchart LR
P["/posts/123"]
R[Router]
M{マッチング}
L["/posts" → List]
F["/posts/new" → Form]
D["/posts/(\d+)" → Detail]
H[DetailHandler]
P --> R
R --> M
M -->|"順番に試す"| L
M -->|"順番に試す"| F
M -->|"マッチ!"| D
D --> H
まとめ URLパターンでハンドラーを振り分ける仕組みをルーターと呼ぶ 正規表現を使ってURLパターンをマッチングする add_routeでパターンとハンドラーを登録するmatchでパスに一致するハンドラーを探す次回予告 次回は、これまで作ってきた機能を統合し、完成したディスパッチャーをBBSに組み込みます。いよいよ完成です。お楽しみに。