テスト用に429のステータスコードを返すREST APIをExpressで簡単に作成する【Node.js】

APIにリクエストの処理に200以外が返ってきたらリトライする処理を追加したが、これの動作確認をどのように行ったら良いのか困った。

その時に自分がテスト用に作ったREST APIの作成方法を記す。

# やること
あくまで429に対する動作検証ができれば良いので、「最初は429を返すけど時間経過で200を返すようになるAPI」を作成する。

使うモジュールはExpressのみ。
（REST APIで429を実装する方法について調べると、専用のモジュール使って、レート設定して、のような複雑な方法がヒットするが、これはあくまで検証用なのでそこまでのことはしない）

# 環境
[Node.js](https://nodejs.org/en)
```
$ node -v
v20.9.0
```
npm
```
$ npm -v
10.0.0
```
[Express](https://expressjs.com/) 4.18.2

# 作成方法
順を追って説明していきます。
## 1.アプリのフォルダを作成
お決まりのいつものやつをやります。
```
$ mkdir <アプリ名>

$ cd <アプリ名>

$ npm init -y
```
## 2.Expressをインストール
```
$　npm install express
```
## 3.まずは200を返すAPIを作成する
`app.js`として以下を作成していきます。
```javascript:app.js
const express = require('express');

const app = express();
const hostname = '127.0.0.1';
const port = 3000;

// アクセス時の処理
app.get('/', (req, res) => {
  res.status(200).send('Success!');
});

// 待ち受け
app.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
```
以下コマンドでアプリを起動します。
```
$ node app.js
```
cURLすると`200 OK`が返ってきていることが確認できます。
```
$ curl -v http://127.0.0.1:3000/
*   Trying 127.0.0.1:3000...
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:3000
> User-Agent: curl/7.80.0
> Accept: */*
>
* Mark bundle as not supporting multiuse        
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: text/html; charset=utf-8        
< Content-Length: 8
< ETag: W/"8-fOAfY4FGM2LPau8vhDpZJh6PVYc"       
< Date: Sat, 28 Oct 2023 16:36:44 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
Success!* Connection #0 to host 127.0.0.1 left intact
```
確認はブラウザアクセスでもOKです。
（「Success!」と表示されます。）
## 4.経過時間によって429を返す処理を追加する
以下のように`app.js`を修正します。
```javascript:app.js
const express = require('express');

const app = express();
const hostname = '127.0.0.1';
const port = 3000;

// 経過時間定義
const waitSec = 30;
const msCoefficient = 1000;
const startTime = Date.now();            // アプリ起動時の現在日時を取得
const blockMs = waitSec * msCoefficient; // 429が解除されるまでの時間（ミリ秒）
const accessible = startTime + blockMs;  // ブロック時間が経過した時点で200を返すようにする


// アクセス時の処理
app.get('/', (req, res) => {
  // アクセス時に日時を取得
  const accessTime = Date.now();
  const elapsed = accessTime - startTime; // アプリ起動してからの経過時間を取得
  const elapsedSec = elapsed / msCoefficient;

  if (accessTime < accessible) {
    // 経過時間が満たない場合
    console.log(`elapsed ${elapsedSec}s`);
    res.status(429).send(`Retry after ${waitSec}s`);
  } else {
    console.log(`elapsed ${elapsedSec}s`);
    res.status(200).send('Success!');
  }
});

// 待ち受け
app.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
```
以下コマンドでアプリを起動します。
```
$ node app.js
```
cURLすると`429 Too Many Requests`が返ってきていることが確認できます。
```
$ curl -v http://127.0.0.1:3000/
*   Trying 127.0.0.1:3000...
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:3000
> User-Agent: curl/8.0.1
> Accept: */*
>
< HTTP/1.1 429 Too Many Requests
< X-Powered-By: Express
< Content-Type: text/html; charset=utf-8
< Content-Length: 15
< ETag: W/"f-WdGFGbRuAhL8vm7ZKodp8PTnlmY"
< Date: Mon, 06 Nov 2023 07:42:28 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
Retry after 30s* Connection #0 to host 127.0.0.1 left intact
```
# おわりに
手軽に429の動作検証したい方の参考になれば。