前回
インターセプタ
インターセプタは、@Injectable()
デコレータがつけられたクラスで、NestInterceptor
クラスを実装します。
インターセプタは、以下が可能です。
- メソッド実行の前後に追加のロジックを実行する
- メソッドから返却された結果を変換する
- メソッドからスローされた例外を変換する
- 基本的な機能の動作を拡張する
- 特定の条件に応じて関数をオーバーライドする
各インターセプタは、intercept()
メソッドを実装します。
intercept()
メソッドは、ExecutionContext
インスタンスと、CallHandler
インスタンスを引数に取ります。
CallHandler
は、インターセプタのある時点でルートハンドラメソッドを呼び出すために使用できるhandle()
メソッドを持ちます。
intercept()
メソッドの実装でhandle()
メソッドを呼び出さない場合、ルートハンドラメソッドは実行されません。
インターセプタの実装
それでは、インターセプタを実装してみましょう。
$ nest g interceptor interceptor/logging
以下のファイルが作成されました。
src/interceptor/logging/logging.interceptor.ts
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'; import { Observable } from 'rxjs'; @Injectable() export class LoggingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { return next.handle(); } }
src/interceptor/logging/interceptor.logging.spec.ts
import { LoggingInterceptor } from './logging.interceptor'; describe('LoggingInterceptor', () => { it('should be defined', () => { expect(new LoggingInterceptor()).toBeDefined(); }); });
インターセプタを修正してみましょう。
src/interceptor/logging/logging.interceptor.ts
import { CallHandler, ExecutionContext, Injectable, NestInterceptor, } from "@nestjs/common"; import { Observable, tap } from "rxjs"; @Injectable() export class LoggingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { console.log("Before..."); const now = Date.now(); return next.handle().pipe( tap(() => { console.log(`after... ${Date.now() - now}ms`); }) ); } }
handle()
は、RxJS Observable
を返却するので、様々な選択肢があります。
ストリームの終了時、または例外終了時にログを出力します。
コントローラにインターセプタをバインドします。
src/cats/cats.controller.ts
import { Body, Controller, Get, Post, UseInterceptors } from "@nestjs/common"; import { CreateCatDto } from "src/dto/cat/cat.dto"; import { Cat } from "./cats.interface"; import { CatsService } from "./cats.service"; import { ValidationPipe } from "../pipe/validation/validation.pipe"; import { LoggingInterceptor } from "src/interceptor/logging/logging.interceptor"; @Controller("cats") @UseInterceptors(LoggingInterceptor) export class CatsController { constructor(private catsService: CatsService) {} @Post() create(@Body(new ValidationPipe()) createCatDto: CreateCatDto) { this.catsService.create(createCatDto); } @Get() findAll(): Cat[] { return this.catsService.findAll(); } }
@UseInterceptors(LoggingInterceptor)
を設置して、バインドしました。
まとめ
ここまでで、
- インターセプタについて
- インターセプタの実装
- インターセプタのコントローラへのバインド
について学びました。
次回は、もう少しインターセプタについて掘り下げようと思います。
コード
今回のコードは、以下に格納しました。