Node.js向けHTTPクライアントGot

普段はクライアントサイドのJSも書くことがあるのでNode.jsではnode-fetch を使っているのですが、StreamAPIが使いたかったりクライアントの層でキャッシュしたくなっていい感じのHTTPクライアントないかなと思って探してみたらGot というライブラリを見つけたので試してみました。

特徴

詳細 はREADME参照ですがいくつかかいつまんでみるとこんな感じです。

  • サイズが軽量でrequest の1/10程度
  • PromiseとStreamAPI両方に対応
  • RFC 7234に準拠したキャッシュ
  • リダイレクトのフォロー
  • リトライ
  • HTTP2は実験的なサポート
  • ブラウザには非対応
  • 名前からお察しの通りググラビリティは壊滅的
  • ライセンスはMIT9.6.0現在)

使い方

インストール

yarnかnpmでインストールするだけでOK。

$ yarn add got

以後のサンプルは9.6.0のものです。

基本的な使い方

Promiseでレスポンスが返ってくる感じで説明不要なくらいシンプル。

const got = require('got');

(async () => {
  try {
    const response = await got('https://example.com');
    console.log(response.body);
  } catch (error) {
    console.log(error.response.body);
  }
})();

GET以外は用意されているメソッドを使う。
リクエストボディでJSONを投げる場合はオプションのjsontrueを設定するとbodyに指定したオブジェクトをJSONに変換して投げてくれるが、jsontrueだとレスポンスボディもJSONじゃないとだめらしくレスポンスがプレーンテキストだったりすると死ぬので注意。

const response = await got.post('https://example.com', {
  body: {
    hello: 'world'
  },
  json: true,
});

console.log(response.body);

StreamAPI

streamというメソッドを使うとPromiseではなくReadableStreamで返ってくる。

got.stream('https://example.com').pipe(writableStream);

ReadableStreamからリクエストを投げたい場合はstreampostメソッドがあるのでpipeする。

readableStream.pipe(got.stream.post('https://example.com'));

キャッシュ

レスポンスを自由にキャッシュできるわけではなくRFC 7234に準拠した形でキャッシュされる。
なのでレスポンスヘッダにexpirescache-controlとかがないと設定してもキャッシュされないっぽい。

一番シンプルな方法は適当なMapオブジェクトを渡せばOK。
二回目のリクエストからはキャッシュがあればキャッシュを返すのでその場合は早い。
キャッシュが返った場合はレスポンスのfromCachetrueになる。

const got = require('got');

const cache = new Map();
const url = 'https://octodex.github.com/images/original.png';

(async () => {
  const first = await got(url, { cache });
  console.log(first.fromCache); // false

  const second = await got(url, { cache });
  console.log(second.fromCache);  // true
})();

Redisなど各種ストレージのアダプタが提供されているのでそれを使えばMap以外に保存できる。
多分インターフェイス合わせれば自作も可能っぽい。

リトライ

設定したステータスコードの場合にリトライする機能。
400番台と500番台全部でリトライするわけではなくデフォルトだとワンチャンありそうなステータスコードの時のみリトライするようになっていてオプションで変更もできる。
リトライ回数だけを指定する場合はリトライ回数だけ指定すればOKで細かいオプションを指定する場合はオブジェクトで設定する。
リトライの間隔は1秒、2秒,4秒,8秒と増えていくタイプ。

const response = await got.get('https://example.com', {
  retry: 3,
});

まとめ

軽量ですが機能はリッチな印象でした。
ドキュメントが量ある割にわかりにくいのとググラビリティが絶望的なのは残念ポイント。

参考リンク