NestJSでリクエストヘッダーに基づくバージョン検出を実現する——ミドルウェアを使用

前回の記事「NestJSでリクエストヘッダーに基づくバージョン検出を実現する——インターセプターを使用」では、インターセプターを使用してバージョンを検出する方法について説明しました。

今回はミドルウェアを例に、その要件を再度実現します。

要件分析

要件は非常にシンプルです:各リクエストのヘッダーにクライアントのバージョン番号を含め、サーバーはこのバージョン番号に基づいて検出を行います。クライアントのバージョンがサーバーが要求する最新バージョンよりも低い場合、レスポンスに更新通知フィールドを追加する必要があります。バージョンが要件を満たしている場合は、データを通常通り返し、変更は加えません。

どのように実装するか

NestJSでは、ミドルウェアを使用してリクエストをキャプチャし、レスポンスを変更することができます。ミドルウェアでは次のことが可能です:

  1. リクエストヘッダーからバージョン情報を取得する
  2. バージョンが更新を必要とするかどうかを判断する、シンプルなバージョン番号の比較で実現します。
  3. レスポンスデータを変更する、更新が必要な場合、返されるデータに追加フィールドを挿入します。

1. バージョン検出ミドルウェアの作成

ミドルウェアは、NestJSでリクエストのライフサイクルに介入するためのツールです。このシナリオでは、クライアントにレスポンスデータを返す前にバージョン検出と処理を行うミドルウェアを作成する必要があります。

1
import { Injectable, NestMiddleware } from "@nestjs/common";
2
import { Request, Response, NextFunction } from "express";
3
4
@Injectable()
5
export class VersionMiddleware implements NestMiddleware {
6
private readonly latestVersion = "2.0.0"; // 最新バージョンを設定
7
8
use(req: Request, res: Response, next: NextFunction) {
9
const version = req.headers["version"] as string; // ヘッダーからバージョン番号を取得
10
11
res.on("finish", () => {
12
if (version && this.needsUpdate(version)) {
13
// 更新が必要な場合、レスポンスデータを変更
14
const originalSend = res.send;
15
res.send = (body: any) => {
16
let modifiedBody = body;
17
try {
18
modifiedBody = JSON.parse(body);
19
} catch (err) {}
20
21
const updateInfo = {
22
updateAvailable: true,
23
updateUrl: "xxxx", // 更新URL
24
latestVersion: this.latestVersion,
25
message:
26
"新しいバージョンが利用可能です。アップデートしてください。",
27
};
28
29
const updatedBody = { ...modifiedBody, ...updateInfo };
30
return originalSend.call(res, JSON.stringify(updatedBody));
31
};
32
}
33
});
34
35
next();
36
}
37
38
// バージョン比較ロジック
39
private needsUpdate(clientVersion: string): boolean {
40
return clientVersion < this.latestVersion;
41
}
42
}

このミドルウェアでは、 req.headers['version'] を使用してクライアントから送信されたバージョン番号を取得し、 needsUpdate メソッドでバージョン比較を行います。クライアントのバージョンが低い場合、レスポンスを送信する前にデータを変更し、 updateAvailable フィールドを追加して新しいバージョンが利用可能であることを通知します。

2. ミドルウェアの適用

NestJSでは、アプリケーションの main.ts または app.module.ts でミドルウェアを登録できます。

app.module.ts での登録

1
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
2
import { AppController } from "./app.controller";
3
import { VersionMiddleware } from "./version.middleware";
4
5
@Module({
6
controllers: [AppController],
7
})
8
export class AppModule implements NestModule {
9
configure(consumer: MiddlewareConsumer) {
10
consumer.apply(VersionMiddleware).forRoutes("*"); // すべてのルートにミドルウェアを適用
11
}
12
}

3. APIのテスト

ミドルウェアの設定が完了したら、curl や Postman を使用してAPIをテストできます。クライアントはリクエストヘッダーを通じてバージョン情報を送信し、サーバーはバージョン番号に基づいて適切なレスポンスを返します。

リクエスト例

Terminal window
1
curl -X GET http://localhost:3000/api/data -H "version: 1.0.0"

レスポンス例(更新が必要な場合)

1
{
2
"data": "Here is your data",
3
"updateAvailable": true,
4
"latestVersion": "2.0.0",
5
"message": "新しいバージョンが利用可能です。アップデートしてください。"
6
}

レスポンス例(更新が不要な場合)

1
{
2
"data": "Here is your data"
3
}

まとめ

ミドルウェアは、ビジネスロジックを変更せずにバージョン検出の要件を処理できる柔軟で効率的な方法です。この方法を使用することで、すべてのAPIリクエストにバージョン管理機能を追加でき、古いバージョンのクライアントが更新通知をタイムリーに受け取れるようになり、ユーザー体験を向上させることができます。この方法は、バージョン管理だけでなく、リクエストとレスポンスの間に処理が必要な他のシナリオ、例えばログ記録や権限検証にも適しています。