[Node.js] Promise版requestでHTTP通信を行う - request-promise-native

前回は非同期なrequestモジュールを利用してHTTP通信を行いましたが、今回は同期処理が行えるrequest-promise-nativeを使っていきます。Promiseが使えます!

準備

3つのモジュールから選択する

Promise対応版のrequestモジュールは歴史的な経緯もあってか次の3種類が用意されています。

request-promise
Promiseの実装としてBluebirdを採用した物。BluebirdはNode.jsやWebブラウザにPromisesの機能がまだ実装されていなかったころから利用されていた便利モジュールです。ごく最近までNodeが提供する公式のPromiseよりも高速で多機能でした。
request-promise-native
Node.jsが提供するPromiseの実装を採用した物。
request-promise-any
Promiseの実装としてAny Promiseを採用した物。

事実上メジャーどころのBluebird版か、Node.jsネイティブ版かの選択になると思うのですが、Bluebirdのドキュメントに次のような記述があります。

Note Promises in Node.js 10 are significantly faster than before. Bluebird still includes a lot of features like cancellation, iteration methods and warnings that native promises don't. If you are using Bluebird for performance rather than for those - please consider giving native promises a shot and running the benchmarks yourself.

bluebird/README.mdより

BluebirdはNode.jsが提供するPromiseよりも高速で省メモリが売りでしたが、Node.js v10から非常に高速になりその優位性が以前ほどありません。しかしながらまだNodeには実装されていない機能があることから、どちらを使うのかは実際にベンチマークを取ってみるのが良いといったことが書かれています。

今回はBluebirdを直接利用するわけではないため、パフォーマンス的にも遜色がないであろうNode.jsが提供する公式のAPIを利用したrequest-promise-nativeを採用したいと思います。

ちなみにGitHubのスターの数は次の通り。過去の歴史によりBluebirdが多いですが今後は逆転していきそうですね。anyは忘れても良いかもしれません。※2019年12月20日時点

リポジトリ Star 1st commit
request-promise 4.4k 2013-10-05
request-promise-native 1k 2016-05-07
request-promise-any 20 2016-05-07

インストール

プロジェクト用の適当なディレクトリ作成し、requestrequest-promise-nativeの2つのモジュールをインストールします。

$ mkdir myrequest2 && cd myrequest2
$ npm init

$ npm install --save request
$ npm install --save request-promise-native

基本的な利用方法

Bluebird版のrequest-promiseと基本的な利用方法は同じなため、ドキュメントはこちらを参照します。

const reqp  = require('request-promise-native');

reqp('https://google.com/')
  .then((html)=>{
    console.log(html);
  })
  .catch((err)=>{
    console.error(err.message);
  })
  .finally(()=>{
    console.log("I am finally.");
  });

GETによる通信になります。見た通りですが通信が成功すればthen()を、失敗すればcatch()が実行されます。finally()は通信結果の成否に限らず常に実行されます。

catch()で補足されるエラーは?

通信中にエラーが発生した場合はもちろんですが、400系/500系のエラーもcatch()で補足されます。もしステータスコード毎に処理を分岐したい場合はerr.statusCodeを参照します。

reqp('http://localhost:3000/404')
  .then((html)=>{
    console.log(html);
  })
  .catch((err)=>{
    switch(err.statusCode){
      case 404:
        console.error("Not Found");
        break;

      case undefined:
      default:
        console.error(err.message);
        break;
    }
  })

例えばオフライン状態であったり途中で切断されるなど、通信自体が正常に行われなかった場合err.statusCodeundefinedになります。

メソッドの指定

同期版と同様の指定が行なえます。以下の場合はPOSTメソッドでの通信になります。

const reqp  = require('request-promise-native');
const options = {
  url: "http://localhost:3000/",
  method: "POST"
};

reqp(options)
  .then((html)=>{
    console.log(html);
  })

また便利関数も同様に利用できます。

const reqp  = require('request-promise-native');

reqp
  .post("http://localhost:3000/")
  .then((html)=>{
    console.log(html);
  })

ここではpost()を利用していますが、その他のget(), put(), head()なども利用可能です。

クエリー/フォームデータの付加

こちらも同期版と同様の指定方法になります。

クエリー

URLのお尻に付加するクエリーは以下の通り。qsというキーで、値にはクエリーとして利用したいハッシュを指定します。

const reqp  = require('request-promise-native');
const options = {
  url: "http://localhost:3000/",
  method: "GET",
  qs: {
    message: "ねこの足跡R",
    date: "2019-12-21"
  }
};

reqp(options)
  .then((html)=>{
    console.log(html);
  })

フォームデータ

POSTメソッドでフォームの値を渡したいときはGETのクエリーとほぼ同じですが、名前をformとします。

const reqp  = require('request-promise-native');
const options = {
  url: "http://localhost:3000/",
  method: "POST",
  form: {
    message: "ねこの足跡R",
    date: "2019-12-21"
  }
};

reqp(options)
  .then((html)=>{
    console.log(html);
  })

参考ページ