blog.bouzuya.net

2014-02-12 Node.jsのWeb API wrapperについてかんがえた

Node.jsのAPI wrapperについてかんがえた。

ぼくは過去Hatena::Graph APIBacklog APIのWeb API wrapperをつくっている。まとめついでに、こういうwrapperのインタフェースについてかんがえてみたい。

Node.js(JavaScript)では関数の呼び出しは非同期の実行になることがままある。そこで使われるのがcallbackを渡す方法。処理が終わったタイミングでcallbackが呼び出される。慣習的にはcallbackの第一引数にはErrorが渡される。例で書くと次のような感じ

var fn = function(params, callback) {
  setTimeout(function() {
    try {
      var result = doSomething(params);
      callback(null, result);
    } catch(e) {
      callback(e);
    }
  }, 1000);
};

fn({ id: 'bouzuya' }, function(err, result) {
  if (err) {
    console.error(err);
  } else {
    console.log(result);
  }
});

ぼくの書いたWeb API wrapperでも類似のインタフェースを採用している。これまではfunction(params, callback)で第一引数にobjectでパラメーター、第二引数にfunctionでcallbackをとるのが汎用的なつくりだと考えてきた。

いま新たに考えているのが、戻り値をもっと使うインタフェースである。具体的に言えば、promiseパターンを採用したい。CommonJS Promiseの実装であるQを使おうかと思っている。

callbackが指定されない場合に戻り値としてpromiseを返す。これを使えば上記の呼び出しを次のように書ける。

fn({ id: 'bouzuya' })
.then(function(result) {
  console.log(result);
})
.fail(function(err) {
  console.error(err);
});

こちらの利点は、関数fnがcallbackをとらずに済むし、callbackの第一引数にerrをとるよりも、分かりやすいと感じる。呼び出し側のテストもしやすい。こういった書きかたはjQueryのdeferredなどでも採用されているので、一般的な気がする。

結論としては、今後ぼくがつくる場合にはfunction(params[, callback])というインタフェースにして、callback省略時にはpromiseを返すようにしたい。またこっそりwrapperを変更しようと思う。