NestJSにおける例外フィルタに関するお勉強記録です。主に以下のページを見て学んだ内容になります。
Exception filters | NestJS - A progressive Node.js framework
例外の基本
まずは例外についての基本的なお話です。
キャッチしていない例外が発生した場合
NestJSはキャッチしていない例外が発生した場合、次の様なレスポンスを返します。
{ "statusCode": 500, "message": "Internal server error" }
スタンダードな例外のthrow
普通にExceptionをnewしてthrowするだけです。第1引数は何かしらのメッセージを、第2引数にはHTTPのステータスコードを渡します。
throw new HttpException("エラーメッセージ", HttpStatus.FORBIDDEN);
勝手にデータを生成して、クライアントには次の様なデータを返します。
{"statusCode":403,"message":"エラーメッセージ"}
以下の様に自分で用意したデータも返せます。
throw new HttpException({"foo":"bar"}, HttpStatus.FORBIDDEN);
次の様にシリアライズされて返ってきます。
{"foo":"bar"}
HttpExceptionを例にしましたが、NestJSではHttpExceptionを継承した以下の様な組み込みの例外クラスが用意されています。
- BadRequestException
- UnauthorizedException
- NotFoundException
- ForbiddenException
- NotAcceptableException
- RequestTimeoutException
- ConflictException
- GoneException
- HttpVersionNotSupportedException
- PayloadTooLargeException
- UnsupportedMediaTypeException
- UnprocessableEntityException
- InternalServerErrorException
- NotImplementedException
- ImATeapotException
- MethodNotAllowedException
- BadGatewayException
- ServiceUnavailableException
- GatewayTimeoutException
- PreconditionFailedException
例外フィルタ
例外をカスタマイズする仕組みです。特定の例外が発生した時だけ特別な処理を実施したりできます。
例外フィルタの作成
NestJSでは以下のコマンドで例外フィルタを作成できます。
nest g filter common/filter/http-exception
作成した直後はこんな感じです。
1 2 3 4 5 6 |
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common'; @Catch() export class HttpExceptionFilter<T> implements ExceptionFilter { catch(exception: T, host: ArgumentsHost) {} } |
これを以下の様に書き換えます。HttpExceptionが発生したらレスポンスにステータスコード、タイムスタンプ、パスを返すようにカスタマイズしてますが、ここでは内容はさして重要ではありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common'; import { Request, Response } from 'express'; @Catch(HttpException) export class HttpExceptionFilter implements ExceptionFilter { catch(exception: HttpException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const request = ctx.getRequest<Request>(); const status = exception.getStatus(); response .status(status) .json({ statusCode: status, timestamp: new Date().toISOString(), path: request.url, }); } } |
cats.controller.tsで使ってみます。@nestjs/commonからuseFiltersをインポートし、create()メソッドと紐づけています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import { Controller, Get, Post, Body, UseFilters, HttpStatus, HttpException } from '@nestjs/common'; import { CreateCatDto } from './dto/create-cat.dto'; import { CatsService } from './cats.service'; import { Cat } from './interfaces/cat.interface'; import { HttpExceptionFilter } from 'src/common/filter/http-exception.filter'; @Controller('cats') export class CatsController { constructor(private catsService: CatsService) { } @Post() @UseFilters(new HttpExceptionFilter()) async create(@Body() createCatDto: CreateCatDto) { throw new HttpException("エラーメッセージ", HttpStatus.FORBIDDEN); } @Get() async findAll(): Promise<Cat[]> { throw new HttpException("エラーメッセージ", HttpStatus.FORBIDDEN); } } |
これでcatsルートへPostすると次の様にhttp-exception.filter.tsで処理された結果が返ってきます。
{"statusCode":403,"timestamp":"2022-05-12T08:31:27.454Z","path":"/cats"}
他にもあれこれ解説されていましたがあまり使わなさそうなので割愛します。一応サンプルコードを置いておきます。