Hatena::ブログ(Diary)

Yet Another Hackadelic

2010-02-23 壊れかけのレイディオ

URI::Template::Restrict 0.04

コラボレータに加えて貰って、0.04 をさっき id:ikasam_a に ShipIt して頂きました。そのうち cpan コマンド等でインストール出来ると思います。id:ikasam_a++

URI::Template::Restrict なんですが、extract() の処理が process() と同様の厳格なルールになっていて、実際に使う際にちょっと困ってました。

例えば、OpenSocial の RESTful API でありがちそうな以下のような URI Template に対して実際の URI をぶつける例、

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dump qw(dump);
use URI::Template::Restrict;

my $t = URI::Template::Restrict->new(
    'http://example.com/api/people/{guid}/{selector}{-prefix|/|personId}'
);

my %uri_params = $t->extract(
    'http://example.com/api/people/@me/@friends/100'
);

print dump(\%uri_params);

これはまったく何もマッチしないんですよね。これは "@" が URI Template 的には vardefault って部分なんですが、この部分の process 時のルールが percent encoding または unreserved って決まってるのでこうなってる。面倒ですね。

と言う訳で extract の時だけルールを緩和して、期待通り、

{ guid => "\@me", personId => 100, selector => "\@friends" }

って感じで取れるようにしたのが 0.04 になります。

ちなみにモバゲーオープンプラットフォームの Avatar API って奴だと、まぁこんな感じの URI Template になります。

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dump qw(dump);
use URI::Template::Restrict;

my $t = URI::Template::Restrict->new(
    'http://example.com/api/avatar/{-list|;|guid}/{selector}/{-join|;|size,view,emotion,dimension,transparent,type,extension}'
);

my %uri_params = $t->extract(
    'http://example.com/api/avatar/100;200;350/@self/size=large;view=entire;transparent=true'
);

print dump(\%uri_params);

__END__
{
  dimension   => undef,
  emotion     => undef,
  extension   => undef,
  guid        => [100, 200, 350],
  selector    => "\@self",
  size        => "large",
  transparent => "true",
  type        => undef,
  view        => "entire",
}

みたいに取れますよっと。

0.03 より loose になってるので互換性の面で難がある場合がありますのでご注意下さいませ。

ちなみにこれで何をしたいかなんだけど、もちろん RESTful API で使うんですけど、HTTP::Router 使った API 専用の薄い WAF を作って使いたいってのがあって、その為にまずは extract が厳格過ぎるってのを直しつつ、次は HTTP::Router の Any::Moose を止めると言う方向性でやりたいなーなんて思ってたりします。