WebService::Simple::Flickrを作りました
前回,Flickr::API を使って Flickr の認証のやり方がわかりましたが,なんか Flickr だけの モジュールを使うのもしゃくなので,ゆーすけべーさんが公開している WebSerivice::Simple を継承して認証できる形のモジュールを作ったので公開します.
WebService::Simple::Flickr
Flickr の認証はちょっと面倒な形をしています.最初に触る API にすべきじゃないです w 何が面倒かというと,パラメータを送るとき,それを並べてハッシュをとったものを 署名として付けないといけない点です.この部分を実装しておきます.
get()関数をオーバーライド
sub get {
my ($self, $args) = @_;
$args->{api_key} = $self->{api_key};
if(defined $self->{api_secret} && length $self->{api_secret}){
if(defined $self->{auth_token} && length $self->{auth_token}){
$args->{auth_token} = $self->{auth_token};
}
$args->{api_sig} = $self->sign_args($args);
}
return $self->SUPER::get($args);
}
まぁコード見てもらえば分かる通りで,Flickr::API からほぼそのまま持って来た sign_args()関数を使ってハッシュを作り,それを api_sig というパラメータで 追加しています.api_key と api_secret はあらかじめ与えておき,auth_token は 後に示す手順で取得しておいて与えておきます.
使い方は,WebService::Simple の get()と同じで,
my $flickr = WebService::Simple::Flickr->new(
api_key => $api_key, api_secret => $secret_key, auth_token => $token);
my $res = $flickr->get({method => "flickr.photosets.getList"});
なんて感じでハッシュにつっこんで get すれば OK.この例の場合,(token が取得して あれば)自分の Set のリストがプライベート設定のやつも含めて取得できているはずです.
コンストラクタもオーバーライド
sub new {
my $class = shift;
my %args = @_;
my $api_key = delete $args{api_key} || "";
my $api_secret = delete $args{api_secret} || "";
my $auth_token = delete $args{auth_token} || "";
my $self = $class->SUPER::new(%args);
$self->{api_key} = $api_key;
$self->{api_secret} = $api_secret;
$self->{auth_token} = $auth_token;
return $self;
}
さっきの例で分かる通り,api_key とかをコンストラクタに渡しちゃってます. よくわかんないですが,とりあえず WebService::Simple のコンストラクタのやってることを パクって,api_key, api_secret, auth_token を持っておくようにします. ちなみに,インスタンス作ったあとに,$flickr->{auth_token}
とかで与えても 大丈夫みたいなので,この実装は要らないかも.
upload_post()メソッドを追加
use base qw(WebService::Simple);
__PACKAGE__->config(
base_url => "http://api.flickr.com/services/rest/",
upload_url => "http://api.flickr.com/services/upload/",
);
....
sub upload_post {
my ($self, $args) = @_;
$args->{api_key} = $self->{api_key};
local $self->{base_url} = $self->config->{upload_url};
my $photo = delete $args->{photo};
if(defined $self->{api_secret} && length $self->{api_secret}){
if(defined $self->{auth_token} && length $self->{auth_token}){
$args->{auth_token} = $self->{auth_token};
}
$args->{api_sig} = $self->sign_args($args);
}
$args->{photo} = [$photo] if ref $photo ne "ARRAY";
return $self->post("", Content_Type => "form-data", Content => $args);
}
Flickr のアップロード用の API は URL が違ったりするし,POST メソッドだったり するので,別に用意します.WebService::Simple の POD の中に例が書いてありますが そのままだと extra_url まわりで失敗するので,post メソッドの最初の変数に空文字列を 与えています.呼び出し方は後の例を参考に.
request_auth_url メソッドを追加
sub request_auth_url {
my ($self, $perms, $frob) = @_;
return undef unless defined $self->{api_secret} && length $self->{api_secret};
my %args = (
'api_key' => $self->basic_params->{api_key},
'perms' => $perms
);
if ($frob) {
$args{frob} = $frob;
}
my $sig = $self->sign_args(\%args);
$args{api_sig} = $sig;
my $uri = URI->new('http://flickr.com/services/auth');
$uri->query_form(%args);
return $uri;
}
これは Flickr::API からまるパクリ.呼び出し方も当然同じ.後で使います.
とりあえずこれを使ってトークンを取得してみよう
前回 Flickr::API でやったことを WebService::Simple::Flickr を使ってやると こんな感じ.
use utf8;
use WebService::Simple::Flickr;
use Data::Dumper;
my $api_key = "*********************************";
my $secret_key = "**********************";
my $flickr = WebService::Simple::Flickr->new(
api_key => $api_key, api_secret => $secret_key);
my $ref;
$ref = $flickr->get({method => "flickr.auth.getFrob"});
my $frob = $ref->parse_response->{frob};
print $frob . "\n";
print $flickr->request_auth_url('write', $frob);
my $line =<stdin>; #表示されるURLにブラウザからアクセスしてOKしたらEnter
$ref = $flickr->get({method => "flickr.auth.getToken", frob =>$frob});
my $token = $ref->parse_response->{auth}->{token};
print $token . "\n";
$flickr->{auth_token} = $token;
$ref = $flickr->upload({photo => "/home/user/image.jpg"});
print Dumper $ref->parse_response;
こんな感じで写真がアップロードできました.やりましたね!
いつも通り github に置いておきます
というわけで,モジュールのソースは github に上げておきます.Plagger とは別の レポジトリを作りました.
perllib/WebService/Simple/Flickr.pm
package WebService::Simple::Flickr;
use Digest::MD5 qw(md5_hex);
use base qw(WebService::Simple);
__PACKAGE__->config(
base_url => "http://api.flickr.com/services/rest/",
upload_url => "http://api.flickr.com/services/upload/",
);
sub new {
my $class = shift;
my %args = @_;
my $api_key = delete $args{api_key} || "";
my $api_secret = delete $args{api_secret} || "";
my $auth_token = delete $args{auth_token} || "";
my $self = $class->SUPER::new(%args);
$self->{api_key} = $api_key;
$self->{api_secret} = $api_secret;
$self->{auth_token} = $auth_token;
return $self;
}
sub api_key { $_[0]->{api_key} }
sub api_secret { $_[0]->{api_secret} }
sub auth_token { $_[0]->{auth_token} }
sub sign_args {
my ($self, $args) = @_;
my $sig = $self->api_secret;
foreach my $key (sort {$a cmp $b} keys %{$args}) {
my $value = (defined($args->{$key})) ? $args->{$key} : "";
$sig .= $key . $value;
}
print "sig=" . $sig . "\n";
return md5_hex($sig);
}
sub get {
my ($self, $args) = @_;
$args->{api_key} = $self->{api_key};
if(defined $self->{api_secret} && length $self->{api_secret}){
if(defined $self->{auth_token} && length $self->{auth_token}){
$args->{auth_token} = $self->{auth_token};
}
$args->{api_sig} = $self->sign_args($args);
}
return $self->SUPER::get($args);
}
sub upload_post {
my ($self, $args) = @_;
$args->{api_key} = $self->{api_key};
local $self->{base_url} = $self->config->{upload_url};
my $photo = delete $args->{photo};
if(defined $self->{api_secret} && length $self->{api_secret}){
if(defined $self->{auth_token} && length $self->{auth_token}){
$args->{auth_token} = $self->{auth_token};
}
$args->{api_sig} = $self->sign_args($args);
}
$args->{photo} = [$photo] if ref $photo ne "ARRAY";
return $self->post("", Content_Type => "form-data", Content => $args);
}
sub request_auth_url {
my ($self, $perms, $frob) = @_;
return undef unless defined $self->{api_secret} && length $self->{api_secret};
my %args = (
'api_key' => $self->basic_params->{api_key},
'perms' => $perms
);
if ($frob) {
$args{frob} = $frob;
}
my $sig = $self->sign_args(\%args);
$args{api_sig} = $sig;
my $uri = URI->new('http://flickr.com/services/auth');
$uri->query_form(%args);
return $uri;
}