argius note

プログラミング関連

WebサービスからJSONを取得してフロントPerlCGIで整形

フロントのWebサーバはPerl,PHP,Rubyくらいしか使えない環境で、アプリ本体はそれ以外で実装したい。
プロキシサーバも使えないので、どうしたものかと思っていたら、Webサービス方式にすれば良かったことに気づいたので、ちょっと試してみました。
データ形式XMLでも良さそうですが、最近はやっぱりJSONが便利みたいなので、JSONでやります。


今回やること

  • 検索結果をJSONで返せるようにする(簡易Webサービス化)
  • PerlCGIから上のWebサービスにアクセスし、結果のJSONを元にHTMLを生成

環境

  • Perl 5.10.0
    • 要JSONモジュール(無かったのでCPANインストール)
  • Play 2.0.4
    • 後述のサンプルの動作環境です

簡易Webサービス

もちろん、これは何で作ってもかまいません。
サンプルとして、Play(scala)で作ったものを載せておきます。
元々は、searchメソッドの結果をHTMLテンプレートに渡すようになっていたのを、JSONでレスポンスを返せるようにしました。
そして、これはちょうど1年前にやった「HerokuでPlay2.0+PostgreSQL」のものなので、Herokuにアップして試しました。

  • controllers/Application.scala
package controllers

import play.api._
import play.api.mvc._
import play.api.libs.json._
import play.api.libs.json.Json.toJson

object Application extends Controller {

  case class Person(name: String, age: Int)

  def index(q: String) = Action {
    implicit object PersonFormat extends Format[Person] {
      def writes(o: Person): JsValue =
        Json.toJson(Map("name" -> toJson(o.name),
                        "age" -> toJson(o.age)))
      def reads(json: JsValue): Person = Person(
        (json \ "name").as[String],
        (json \ "age").as[Int])
    }
    val records: Seq[Person] = search(q)
    Ok(toJson(Map("records" -> records)))
  }

  private def search(q: String): Seq[Person] = Seq() // 検索結果を返す

}

返されるJSONはこんな感じです。

{"records": [
    { "name" : "Suzuki Jiro", "age": 34 },
    { "name" : "Matsui Hiroyuki", "age": 56 }
 ]}

フロントのPerlCGI

URLはダミーです
特に難しいことはやっていません。

use strict;
use warnings;
use utf8;
use Encode;
use CGI;
use URI::Escape;
use LWP::UserAgent;
use JSON;

my $cgi = new CGI;
my $q = $cgi->param("q"); # parameter
my $url = "http://example.com/search?query=" . uri_escape(encode('utf-8', $q));
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new("GET", $url);
my $res = $ua->request($req);

# HTML
print "Content-Type: text/html; charset=utf-8\n\n";
print "<html><body>";
if ($res->is_success) {
  my $json = JSON->new->utf8(0)->decode(decode_utf8($res->content));
  my $i = 0;
  my $records = $json->{records}; # Array Ref
  print "<h1>List</h1><p>Q=[$q]</p><ul>";
  for my $r (@{$records}) {
    printf "<li>No.%04d: name=%s, age=%s</li>", ++$i, $r->{name}, $r->{age};
  }
  print "</ul>";
}
else {
  print "<p>ERROR</p>";
}
print "</body></html>";

まとめ

実際にやってみるまでは、いろいろ制限があってつまずくかな、と思いきや、あまりに普通に出来たので拍子抜けしてしまいました。PerlのJSONモジュールくらいですね。
でもそれは、グーグル先生とJSONさんがあればこそですね。サマサマです。


ミッションクリティカルなどのシビアな性能が求められるシステムには向かないでしょうが、そうでなければ分散が簡単に実現できるのが良いかなと思います。