有料になった exchangeratesapi.io を無料の範囲内で使い倒すnpmパッケージを作ってみた

# 背景

無料かつ登録不要で使える為替取得APIとして [exchangeratesapi.io](https://exchangeratesapi.io/)が有名でしたが、ついに2021年4月から登録必須＆一分機能は有料のサブスクリプション契約が必須になってしまいました。

2021/04/03時点で、月額費用と使える機能は以下のようになっているようです。
個人的な記憶を頼りに、2021年3月まで無料で使えた機能についても並べています。

|機能|〜2021年3月<br>無料機能|`Free`|Basic|Professional|Business|
|---|:---:|:---:|:---:|:---:|:---:|
|月額|無料|無料|$10|$40|$80|
|月間リクエスト数|無制限|~~250~~<br />1,000|10,000|100,000|500,000|
|更新頻度|1日|1日|1時間|10分|60秒|
|履歴取得|✅|✅|✅|✅|✅|
|HTTPS対応|✅||✅|✅|✅|
|基準通貨の切り替え|✅||✅|✅|✅|
|為替換算|||✅|✅|✅|
|時間枠クエリ||||✅|✅|
|為替変動クエリ|||||✅|
|サポート|なし|限定的|Basic|Premium|Premium|

新たなFreeプランの場合、`リクエスト数は大きく制限`されますが、1日1回しか更新されないデータなので250回/月もあれば、個人利用やちょっとしたバッチ処理程度であれば十分に感じます。
なお、[Pricing](https://exchangeratesapi.io/pricing/)ページにはFreeプランの月間リクエスト数は250ですが、登録後のダッシュボード画面では1,000になっていました。

`HTTPS対応していない`点については、もともとオープンデータを取得するだけのAPIなので大きなリスクにはならないように思います。ただ、APIキーが丸見えになるので、APIキーを抜かれて勝手に使われる可能性くらいは頭に入れておく必要があります。

次の`基準通貨の切り替えができなくなる`点ですが、個人的にはこれが最もインパクトの大きい変更だと感じています。EU中央銀行のデータを使っていることもあり、このAPIのデフォルトの基準通貨は`EUR`です。
たとえば`USDとJPYのレートを取りたい！`という時、従来は`USD基準のJPYのレートを取得`というリクエストができたものの、新たなFreeプランでは`EUR基準のUSDとJPYのレートを取得`というリクエストを投げた上で、自ら換算処理を行う必要が出てきます。
これが面倒くさい場合は、$10以上課金してBasicプランにする必要があります。

また、為替換算についても、無料枠のAPIで取得したデータを使って自分で換算処理を実装することで、対応可能です。

# 無料枠のAPIだけで有料相当の機能を作ってみた

ということで、新たなAPIについて考察していると、かなり機能は制限されたことはわかりましたが、無料枠のAPIにちょっとした換算ロジックを組み合わせると、有料で提供されている機能に相当するものを作れるような気がしてきたので、Node.jsで実際に作ってみました。

## @ittkm/exchangeratesapi

[![npm version](https://img.shields.io/npm/v/@ittkm/exchangeratesapi.svg)](https://www.npmjs.com/package/@ittkm/exchangeratesapi) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](./LICENSE) [![Build Status](https://travis-ci.org/itTkm/exchangeratesapi.svg?branch=main)](https://travis-ci.org/itTkm/exchangeratesapi) [![Coverage Status](https://coveralls.io/repos/github/itTkm/exchangeratesapi/badge.svg?branch=main)](https://coveralls.io/github/itTkm/exchangeratesapi?branch=main)

https://www.npmjs.com/package/@ittkm/exchangeratesapi

https://github.com/itTkm/exchangeratesapi#free-client-for-exchangeratesapiio

## できること

このパッケージで網羅している機能を、先程の一覧表に反映するとこんな感じです。

|機能|〜2021年3月<br>無料機能|`NEW`|Free|Basic|Professional|Business|
|---|:---:|:---:|:---:|:---:|:---:|:---:|
|月額|無料|無料|無料|$10|$40|$80|
|月間リクエスト数|無制限|~~≦ 250~~<br />≦ 1,000|~~250~~<br />1,000|10,000|100,000|500,000|
|更新頻度|1日|1日|1日|1時間|10分|60秒|
|履歴取得|✅|✅|✅|✅|✅|✅|
|HTTPS対応|✅|||✅|✅|✅|
|基準通貨の切り替え|✅|✅||✅|✅|✅|
|為替換算||✅||✅|✅|✅|
|時間枠クエリ||✅|||✅|✅|
|為替変動クエリ||||||✅|
|サポート|なし|なし|限定的|Basic|Premium|Premium|

さすがに、HTTPS対応はAPI側の話なので対応できませんが、従来の無料機能よりも多機能になりました。
月間リクエスト数が少し減るのは、`時間枠クエリ`を使用する場合です。（裏で指定された日数分のAPIリクエストを行うため）

なお、レスポンスは有料版のAPI仕様に合わせてあるため互換性があります。

exchangeratesapi.io の有料化で頭を抱えている方の一助になれば幸いです。

## 以下、READMEの日本語訳

### インストール

```bash
# via npm
npm install --save @ittkm/exchangeratesapi

# via yarn
yarn add @ittkm/exchangeratesapi
```

### 使い方

```js
import exchangeratesapi from "@ittkm/exchangeratesapi";
// // または
// const exchangeratesapi = require("@ittkm/exchangeratesapi").default;

// https://exchangeratesapi.io/ で取得したAPIキーに書き換えてください
const API_KEY = "1234567890abcdefghijklmnopqrstuv";

async function exchangeratesapiSamples() {
  // API Keyを使って初期化
  const api = new exchangeratesapi(API_KEY);

  // 好きなAPIを呼び出す
  const exchangeRates = await api.latest();
  console.dir(exchangeRates);
}
```

### 使用例

```js
/**
 * 最新レート取得 (初期設定)
 *  - 基準通貨: EUR
 *  - 対象通貨: すべて
 */
console.dir(await api.latest());

/**
 * 最新レート取得
 *  - 基準通貨: USD
 *  - 対象通貨: GBP, JPY, EUR
 */
const latestParameters = {
  base: "USD",
  symbols: ["GBP", "JPY", "EUR"],
};
console.dir(await api.latest(latestParameters));

/**
 * 日付指定で取得 (初期設定)
 *  - 日付未指定で最新レートを取得
 *  - 基準通貨: EUR
 *  - 対象通貨: すべて
 */
console.dir(await api.historical({}));

/**
 * 日付指定で取得
 *  - 対象日: 2013-12-24
 *  - 基準通貨: GBP
 *  - 対象通貨: USD, CAD, EUR
 */
const historicalParameters = {
  date: "2013-12-24",
  base: "GBP",
  symbols: ["USD", "CAD", "EUR"],
};
console.dir(await api.historical(historicalParameters));

/**
 * 為替換算 (最新レート)
 *  - GBP から JPY
 *  - 数量: 25
 */
console.dir(
  await api.convert({
    from: "GBP",
    to: "JPY",
    amount: 25,
  })
);

/**
 * 為替換算 (過去のレート使用)
 *  - GBP から JPY
 *  - 数量: 25
 *  - 対象日: 2018-02-22
 */
const convertParameters = {
  from: "GBP",
  to: "JPY",
  amount: 25,
  date: "2018-02-22",
};
console.dir(await api.convert(convertParameters));

/**
 * 時間枠指定で取得 (最小オプション)
 *  - 対象通貨: すべて
 */
console.dir(
  await api.timeseries({
    start_date: "2012-05-01",
    end_date: "2012-05-03",
  })
);

/**
 * 時間枠指定で取得 (通過指定)
 *  - 基準通貨: EUR
 *  - 対象通貨: USD, AUD, CAD
 */
const timeseriesParameters = {
  start_date: "2012-05-01",
  end_date: "2012-05-03",
  base: "EUR",
  symbols: ["USD", "AUD", "CAD"],
};
console.dir(await api.timeseries(timeseriesParameters));
```

### レスポンス

[exchangeratesapi.io](https://exchangeratesapi.io/)のレスポンスと互換性があります。

詳細は[公式ドキュメント](https://exchangeratesapi.io/documentation/)を参照してください。