俗に言う「REST/XML over HTTP POX over HTTP」のウェブAPIにアクセスするためのシンプルな(?)Perlモジュール「WebService::Simple」なるものを作ってみました。REST/XML over HTTP POX over HTTP というのは、俺の解釈でいいますと、パラメータを指定して GET (POSTの場合もある)により情報の入ったコンテンツをXML形式で取得するというものです。WebService::Simple は基本的にこれ従っていればどんな API にも対応しているはずです。もしくはそうしたいです。
追記: masakiさんからTwitter経由で突っ込みをもらったので修正しておきました。確かにRESTという言葉が入っていると誤解されちゃいますよね>< 参考: POX over HTTP - naoyaのはてなダイアリー
@yusukebe あれで REST とか言うと誤解を生むから POX over HTTP と言って欲しい
最近こうしたウェブAPIを利用するためのプログラムをいくつか作っているのですが、何回も同じ処理をコピペしているのに気づいて、短いコードながらも(50行くらいだよ)モジュール化してみたという経緯です。 ウェブAPI を利用するには、
- リクエストURLの作成
- コンテンツの取得
- XMLのパース
という3ステップがあるので、この処理を「WebService::Simple」に任せるようにしました。 XMLのパースには個人的に扱いやすいと思っている XML::Simple を使っているため、返却される値はPerlオブジェクトのリファレンスとなります。
例としてFlickrのAPIを挙げます。キーワードで写真を検索して結果をダンプするスクリプトは、WebService::Simple を使わないとしたら以下のように書けます。
#!/usr/bin/perl use strict; use warnings; use LWP::Simple; use XML::Simple; use URI::Escape; use YAML; use utf8; binmode STDOUT, ":utf8"; my $api_key = "your_api_key"; my $url = make_url( "flickr.photos.search", { text => "猫" } ); my $content = get($url) or die "Couldn't get xml"; my $xs = XML::Simple->new( forcearray => ["photo"], keyattr => [] ); my $results = $xs->XMLin($content); print Dump $results; sub make_url { my ( $method, $param ) = @_; my $url = "http://api.flickr.com/services/rest/?"; $url .= "method=$method&api_key=$api_key"; foreach my $key ( keys(%$param) ) { $url .= "&$key=" . URI::Escape::uri_escape_utf8( $param->{$key} ) . "&"; } return $url; }
上記した3つのステップがコード内に入っています。では次に、WebService::Simpleを使ったサンプルコードはこちらとなります。
#!/usr/bin/perl use strict; use warnings; use WebService::Simple; use YAML; use utf8; binmode STDOUT, ":utf8"; my $api_key = "your_api_key"; my $base_url = "http://api.flickr.com/services/rest/"; my $flickr = WebService::Simple->new( $base_url, { api_key => $api_key } ); my $response = $flickr->get( { method => "flickr.photos.search", text => "猫" } ); my $ref = $response->parse_xml( { forcearray => ["photo"], keyattr => [] } ); print Dump $ref;
リクエストURLを作るのとXML::Simpleのインスタンスを作成してパースという処理が無くなったためコードがすっきりしました。また、パラメータをハッシュリファレンスで指定するので、いろいろな種類のリクエストを作るのが楽です。WebService::Simple のメソッドは以下の通りです。
- new
- 第一引数にAPIのベースURL、 第二引数にアプリケーションIDなどそのAPIを使うにあたって常に必要になってくるパラメータを指定
- get
- 引数にはパラメータと値が格納されたハッシュリファレンスを渡す。 HTTP::Responseオブジェクトにparse_xmlというメソッドを追加した WebService::Simple::Response オブジェクトが返ってくる
getメソッドで返される WebService::Simple::Response オブジェクトの parse_xml のパラメータには、XML::Simple の new で指定するものをハッシュリファレンスで渡してあげます。するとXML::SimpleでXMLコンテンツをパースしたリファレンスが返ってきます。
もちろん Flickr 以外のAPIのアクセスにも使えて、Amazon で書籍検索するサンプルはこんな感じです。
#!/usr/bin/perl use strict; use warnings; use WebService::Simple; use YAML; use utf8; binmode STDOUT, ":utf8"; my $access_key = "your_access_key"; my $associate_tag = "your_associate_tag"; my $base_url = "http://webservices.amazon.co.jp/onca/xml"; my $param = { Operation => "ItemSearch", SearchIndex => "Books", Keywords => "perl", ResponseGroup => "Small,Images", }; my $amazon = WebService::Simple->new( $base_url, { Service => "AWSECommerceService", SubscriptionId => $access_key, AssociateTag => $associate_tag, } ); my $response = $amazon->get($param); my $ref = $response->parse_xml( { forcearray => [ "item", "Author" ], keyattr => [] } ); print Dump $ref;
ようは、ウェブAPIを使う時に、リクエストURLをいちいち作るのめんどくせーよ、返ってきたXMLは(処理が遅くてもいいから扱いやすい)XML::Simpleで返してよ!という超個人的な要望を叶えるモジュールです。 今後欲しい機能として、API のアプリケーションIDなどを YAML で設定ファイルとして持たせて、それを自動的に読んだりしたら楽チンだなと思っています。 例によって CodeRepos で管理することにしましたので興味がある人は覗いてください。 そして突っ込み、添削大歓迎です。