Vert.xでFlickrのクライアントとHTTPサーバーを実装する

[Instant Vert.x](http://www.amazon.co.jp/Instant-Vert-x-Simone-Scarduzio-ebook/dp/B00ESX17RA/ref=pd_sim_kinc_2/377-6400425-9638145?ie=UTF8&refRID=1Z1PC90AV96NTGM6HGRF "Instant Vert.x")を読みながらサンプルコードを試してみる。  
今回はHttpServerとHttpClient(Flickr)。  
まずはクライアント側のコード

```Java

public class ClientVerticle extends Verticle {

  HttpClient client;

  public void start() {
    container.logger().info("ClientVerticle deployed.");
    client = vertx.createHttpClient();
    client.setHost("ycpi-api.flickr.com").setPort(80);
    vertx.eventBus().registerHandler("webclient_address", this::handleClientEvent);
  }

  void handleClientEvent(Message<String> msg) {
    container.logger().info(Rythm.render("Recieved tag:@tag", msg));
    client.getNow(
        Rythm.render("/services/feeds/photos_public.gne?tags=@message&format=json", msg.body()),
        (HttpClientResponse res) -> {
      container.logger().info(Rythm.render("Got response. status_code=[@status].", res.statusCode()));
      res.bodyHandler((Buffer body) -> {
        String json = body.toString();
        // かっこに囲まれた変なJSONを返すので削る。
        json = json.substring(json.indexOf('(') + 1, json.length() - 1);
        json = json.replaceAll("\\\\'", "'");
        msg.reply(json);
      });
    });
  }
}
```

EventBusの"webclient_address"というアドレスでイベントが着火するとイベントのメッセージに書かれたキーワードを使ってFlickrのAPIから画像を集めてきます。  
FlickrのAPIは特別な認証が必要ないですが、JSONとしてパースするにはレスポンスをちょっと成形する必要があります。  
続いてサーバー側のコード


```Java
public class ServerVerticle extends Verticle {

  public void start() {
    container.deployVerticle(ClientVerticle.class.getCanonicalName());
    HttpServer server = vertx.createHttpServer();
    RouteMatcher routeMatcher = new RouteMatcher();
    routeMatcher.get("/tag/:theTag", this::handleTag);
    routeMatcher.getWithRegEx(".*", this::handleOthers);
    server.requestHandler(routeMatcher).listen(8080);
  }

  private void handleTag(HttpServerRequest req) {
    String tag = req.params().get("theTag");
    container.logger().info(Rythm.render("Looking for:@searchWord", tag));
    vertx.eventBus().send("webclient_address", tag, (Message<String> result) -> {
      String json = result.body();
      JsonObject jsonObj = new JsonObject(json);
      String html = Rythm.render(PAGE_TEMPLATE, tag, jsonObj.getArray("items"));
      req.response().end(html);
    });
  }

  private void handleOthers(HttpServerRequest req) {
    req.response().end("ERROR: fill the tag.");
  }

  private static final String PAGE_TEMPLATE =
      "@import org.vertx.java.core.json.JsonArray\n"
      + "@import org.vertx.java.core.json.JsonObject\n"
      + "@args String searchWord, JsonArray items\n"
      + "<html><h1>Result for @searchWord </h1>\n"
      + "@for(items) {\n"
      + "@{ JsonObject item = (JsonObject)_; }\n"
      + "<h3>@item.getString(\"title\")</h3>\n"
      + "<a href=\"@item.getString(\"link\")\">"
      + "<img src=\"@item.getObject(\"media\").getString(\"m\")\" />"
      + "</a>\n"
      + "}\n" + "</html>";
}

```

start()ではクライアントのVerticleをデプロイした後、RouteMatcherを使ってHTTP Serverで受け取るリクエストののルーティングを行っています。  
クライアント側で書いたコードをこちらのVerticleに書いても問題なく動作しますが、プログラムの関心事毎にVerticleを作る方がよかろうとのことです。（例えば、データベースへの接続、WEBサーバー、認証、キャッシュ、など）  
サーバーがレスポンスとして返却するHTMLのレンダリングには[Rythm](http://rythmengine.org/)というテンプレートエンジンを使っています。  

Verticleを実行した後はブラウザから[http://localhost:8080/tag/cat](http://localhost:8080/tag/cat)にアクセスすると、ClientVerticleが猫の画像を集めてきて、ServerVerticleが集めた猫の画像を並べたHTMLをブラウザに返却します。


今回のソースコードは[こちら](https://github.com/jkugiya/vertx-httpsample)にあります。