koaで画像拾ってきてそのまま返すyieldableでスマートな処理

Koa Node.js JavaScript
0 Comments
Tweet

別のサーバーにある画像ファイルを、koaで動作しているサービスから渡す必要に迫られました。
そんなときにもkoa。スマートに仕上げてくれます。

コード (sample.js)

var koa = require('koa');
var route = require('koa-route');
var app = koa();
//-- ここから下はcoのサンプルから
var thunkify = require('thunkify');
var request = require('request')
.defaults({ encoding: null }); //←これがミソ!
var get = thunkify(request.get);
//!-- ここまで

app.use(route.get('/hoge.png', function *(){
var url = 'http://www.google.co.jp/images/srpr/logo11w.png';
var img = yield get(url);
this.type = img[0].headers['content-type']; //ヘッダー付ける
this.body = img[1]; //Bufferオブジェクト
}));

app.listen(3000);

実行

node --harmony sample.js

結果

curl -v localhost:3000/hoge.png
もしくは
open http://localhost:3000/hoge.png (OS X限定)

スクリーンショット 2014-04-23 1.25.49.png

まとめ

yieldを使った非同期処理を同期っぽくこなす場合はその処理がyieldableである必要があります。
httpをつかったファイルのダウンロードをyieldableな処理で実行するサンプルコードは、koaのベースとなるCoのReadmeに書いてあります。
今回はそちらの利用方法を参考にさせてもらいました。

Coにあるサンプルコードのままでは、バイナリデータを扱うようなことはできません。
request.getが取得したデータをテキストとして解釈してしまうためです。
それを防ぐために、default({ encoding: null })とオプションを指定します。
これで正常にバイナリデータをBufferとして扱えるようになります。

JSONオブジェクトを渡した際は、Content-Typeがapplication/jsonにセットされていたのですが、今回のようにBufferが渡された場合は、application/octet-streamがセットされてしまいます。
仕方がないので、this.typeにダウンロードしたファイルのHTTPヘッダ情報から得たContetn-Typeを入れてあげます。

そこまでスマートではないですが、今までのcallback地獄よりはきれいに書けると思います。

koa、使わない手はないでしょう。