← 解説「ミドルウェア — ルーティング前の共通処理」に戻る
サンプルコードで身につける: ミドルウェア — ルーティング前の共通処理
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1最小のロガーミドルウェア
全リクエストのメソッドとURLを記録する最小のミドルウェアです。どのハンドラに振り分けられるか決まる前に動くこと、最後に next() でバトンを渡すことという2つの基本を示します。
import { Injectable, NestMiddleware } from "@nestjs/common";
import { Request, Response, NextFunction } from "express";
@Injectable()
export class RequestLogMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log(
new Date().toISOString() + " " + req.method + " " + req.originalUrl,
);
next(); // 次の処理へバトンを渡す(忘れると止まる)
}
}
// どのハンドラが担当するか決まる前に、全リクエストへ触れる
2関数スタイルのミドルウェア
状態を持たない単純な処理ならクラスではなく関数でも書ける、という軽量スタイルです。Express 向けに公開されている既存ミドルウェアがまさにこの形なので、資産流用の受け皿としても重要です。
import { Request, Response, NextFunction } from "express";
// 依存の注入が不要な単純な処理は、関数のままでよい
export function requestLogger(
req: Request,
res: Response,
next: NextFunction,
) {
console.log(req.method + " " + req.originalUrl);
next();
}
// Express 用の既存ミドルウェア(helmet, morgan など)も
// この形なので、consumer.apply(...) にそのまま渡して流用できる
3next() のバトンリレーを再現
ミドルウェアが next() でつながるバトンリレーの構造をプレーン TypeScript で再現した例です。next() を呼び忘れたミドルウェアで処理が止まり、ハンドラに到達しなくなる様子を実際に確かめられます。
TypeScript
4適用範囲の指定と除外
configure() でミドルウェアの効かせ先を細かく制御する例です。全パスに適用しつつヘルスチェックだけ除外する設定は、監視の大量アクセスでログが埋まるのを防ぐ実務頻出のパターンです。
import { MiddlewareConsumer, Module } from "@nestjs/common";
import { RequestLogMiddleware } from "./request-log.middleware";
@Module({})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(RequestLogMiddleware)
.exclude("health") // ヘルスチェックはログに残さない
.forRoutes("{*path}"); // NestJS v11(Express 5)の全ルート指定
}
}
// 監視ツールの定期アクセスでログが埋まるのを防ぐ、定番の除外設定
5リクエストIDの付与
最前段で全リクエストに一意の ID を振る実務ミドルウェアです。以降のログにこの ID を含めれば、障害調査のときに「この1リクエストに関するログ」だけを横断検索できるようになります。
import { Injectable, NestMiddleware } from "@nestjs/common";
import { Request, Response, NextFunction } from "express";
@Injectable()
export class RequestIdMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
// 最前段で全リクエストに ID を振っておく
const requestId = Math.random().toString(36).slice(2, 10);
req.headers["x-request-id"] = requestId;
res.setHeader("x-request-id", requestId); // クライアントにも返す
next();
}
}
// 以降のログに ID を含めると、障害調査で
// 「この1リクエストのログ」だけを横断検索できる