NestJSのInterceptorは、リクエストとレスポンスの処理の前後に共通処理を挟み込むことができる仕組みです。
ここでは、リクエストごとにログを出力し、レスポンスの形を統一する方法を紹介します。
1. ログ出力用インターセプターの作成
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable, tap } from 'rxjs';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const { method, url } = request;
const now = Date.now();
// レスポンス送信後にログ出力
return next.handle().pipe(
tap(() => {
const ms = Date.now() - now;
// ログ出力(ここではconsole.logですが、Loggerサービスに置き換え可能)
console.log(`[${method}] ${url} - ${ms}ms`);
}),
);
}
}
2. レスポンス整形用インターセプターの作成
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class TransformResponseInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map((data) => ({
success: true,
data, // 実際のレスポンスデータ
})),
);
}
}
3. インターセプターの適用方法
グローバルに適用する場合(main.ts)
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { LoggingInterceptor } from './logging.interceptor';
import { TransformResponseInterceptor } from './transform-response.interceptor';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(
new LoggingInterceptor(),
new TransformResponseInterceptor(),
);
await app.listen(3000);
}
bootstrap();
コントローラーやメソッド単位で適用する場合
import { UseInterceptors } from '@nestjs/common';
@UseInterceptors(LoggingInterceptor, TransformResponseInterceptor)
@Controller('sample')
export class SampleController {
// ...
}
補足
- ログ出力は、
console.log
の代わりにNestJSのLogger
サービスを使うと、より実用的です。 - レスポンス整形は、APIの返却形式を統一したい場合に便利です。
- インターセプターは複数同時に適用可能です。