はじめに
APIのリクエスト処理を作成した際に、ステータスコードが429(Too Many Requests)で返ってきてヒヤっとした経験はないでしょうか?
サードパーティのAPIを利用する場合には、プロバイダがAPIのリクエスト頻度を制限していることが一般的です(例えば、1秒間に10回までなど)
上記の理由で、リクエスト頻度を意識する必要があります
Node.js には、AxiosというHTTPクライアントライブラリがあります
本記事では、Axiosにリクエスト間隔を設定する方法の一例を紹介したいと思います!
ゴール
axiosを使って、APIのリクエスト間隔を制御できる
環境情報
項目 | バージョン |
---|---|
Node.js | 20.11.1 |
TypeScript | 5.4.3 |
Axios | 1.6.8 |
方針
以下の方針で実装をしていきます
- axiosのインスタンス単位でリクエスト間隔を制御する
- 同一インスタンスを使用して、リクエストする場合にはあらかじめ設定したリクエスト間隔を守ってリクエストを行う
- 異なるインスタンスでは、それぞれ独立してリクエスト間隔を設定できる
- axiosのinterceptorsの機能を利用して、リクエストに対して待機処理を追加する
- axios.createの使用感を維持するため、引数の拡張で対応する
interceptors
axiosには、interceptorsがあります
interceptorsを使用することで、リクエストやレスポンスの処理の前に特定の処理を差し込むことができます
今回は、このinterceptorsを使用して、APIリクエスト前にあらかじめ指定したミリ秒だけ待機するようにします
実装例
以下のフォルダ構成でサンプルを作成してみます
-
project-root/
-
api/
sampleApiClient.ts
-
utils/
axios.ts
index.ts
-
utils/axios.ts
axios.create
を拡張し、リクエスト間隔を調整できるaxiosEx.create
を定義します
import axios from "axios";
const createAxiosInstance: CreateAxiosInstance = ({
interval = 0,
...param
} = {}) => {
const instance = axios.create(param);
// 間隔が必ず0ミリ秒以上になるように調整する
const requestInterval = interval > 0 ? interval : 0;
if (requestInterval > 0) {
instance.interceptors.request.use(async (config) => {
await sleep(requestInterval);
return config;
});
}
return instance;
};
const sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));
// exportして他のファイルから呼び出せるようにする
export const axiosEx = {
create: createAxiosInstance,
};
// 以下、型定義
type Axios = typeof axios;
type AxiosCreate = Axios["create"];
type AxiosCreateParam = Parameters<AxiosCreate>[0];
type AxiosCreateReturn = ReturnType<AxiosCreate>;
type AxiosExCreateParam = AxiosCreateParam & {
/**
* リクエスト間の待機時間 [ms]
* @default 0
*/
interval?: number;
};
type AxiosExCreateReturn = AxiosCreateReturn;
type CreateAxiosInstance = (params?: AxiosExCreateParam) => AxiosExCreateReturn;
api/sampleApiClient.ts
axiosEx.create
を呼び出して、axiosのインスタンスを用意します
リクエスト間隔を指定するinterval
には、500ミリ秒を指定しておきます
import {axiosEx} from "../utils/axios";
// exportして他のファイルから呼び出せるようにする
export const sampleApiClient = axiosEx.create({
baseURL: "http://localhost:3000",
interval: 500, // [ms]
});
index.ts
sampleApiClient
を呼び出します
import {sampleApiClient} from "./api/sampleApiClient";
const main = async () => {
const names = [
"Noby",
"Sue",
"Big G",
"Sneech",
"Doraemon",
];
// 配列の処理が非同期で行われないように、呼び出し側で要注意
for (const name of names) {
// 500ms待ってから、APIリクエストを行う
const { data } = await sampleApiClient.get<string>("/api/hello", {
params: { name },
}).catch((error) => {
console.error(error);
throw error;
});
console.log(data); // e.g. Hello, Noby!
}
};
main();
まとめ
今回は、axiosで簡易的にリクエスト間隔を調整する方法を紹介しました
(別の方法としてaxiosのインスタンスをステートフルにしてタイムスタンプを管理するようにしたら、より厳密にリクエスト間隔を調整できそうな気がします)
理想を言えば、axiosが公式にAPIのリクエストの間隔を設定できるようなアップデートがあると嬉しいです
↓ 今回試した内容はGithubに公開しています。よければ参考にしてください