NestJS는 기본적인 Exception을 처리하는 Exception Layer가 존재합니다.
@nestjs/common
에 있는 HttpException Class
를 사용하면 표준 예외 처리가 가능합니다.
@Get()
async findAll(){
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
// 예외 출력
//{
// "statusCode": 403,
// "message": "Forbidden"
//}
표준 HttpException을 상속받아 Custome Exception을 생성할 수 있습니다.
export class ForbiddenException extends HttpException {
constructor() {
super('Forbidden', HttpStatus.FORBIDDEN);
}
}
@Get()
async findAll() {
throw new ForbiddenException();
}
cause
매개변수를 통해 오류설명을 제공할 수 있습니다.
throw new BadRequestException('Something bad happened', { cause: new Error(), description: 'Some error description' })
// 출력
// {
// "message": "Something bad happened",
// "error": "Some error description",
// "statusCode": 400,
// }
NestJS
에서 제공하는 기본 예외 필터를 제공하지만, 새로운 예외 필터가 필요할 수 있습니다.
그럴 경우 ExceptionFilter interface
를 구현하여 새로운 예외 필터를 만들어 사용하면 됩니다.
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,
});
}
}
@Catch
데코레이터를 통해 특정 예외만 필터가 처리하도록 합니다.
이때 쉼표로 구분지어 리스트로 매개변수 입력이 가능하여, 여러 유형 예외 처리가 가능합니다.
exception
: 현재 처리 중인 예외 객체
host : ArgumentHost
: 요청 및 응답 객체에 대한 참조를 가진 객체
@UseFilters
데코레이터를 통해 필터 바인딩이 가능합니다.
이때 바인딩 범위는 작게는 컨트롤러 함수 단위부터 전역 단위까지 가능합니다.
컨트롤러 특정 함수에 적용
@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
throw new ForbiddenException();
}
컨트롤러 전체에 적용
@UseFilters(new HttpExceptionFilter())
export class CatsController {}
전역 단위로 적용
//main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(3000);
}
bootstrap();
위의 예외 필터에서는 @Catch(HttpException)
데코레이터를 통해 HttpException
만 처리합니다.
이때 @Catch()
매개변수를 비워두면 모든 Exception
에 대해 처리가 가능합니다.
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
constructor(private readonly httpAdapterHost: HttpAdapterHost) {}
catch(exception: unknown, host: ArgumentsHost): void {
// In certain situations `httpAdapter` might not be available in the
// constructor method, thus we should resolve it here.
const { httpAdapter } = this.httpAdapterHost;
const ctx = host.switchToHttp();
const httpStatus =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const responseBody = {
statusCode: httpStatus,
timestamp: new Date().toISOString(),
path: httpAdapter.getRequestUrl(ctx.getRequest()),
};
httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus);
}
}
이때 생성자로 HttpAdapterHost
를 넘겨줘야하므로 다음과 같이 설정한다.
import { HttpAdapterHost, NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './common/exception/all-exception.filter';
import { HttpExceptionFilter } from './common/exception/http-exception.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const httpAdapter = app.get(HttpAdapterHost);
app.useGlobalFilters(
new HttpExceptionFilter(),
new AllExceptionsFilter(httpAdapter),
);
await app.listen(3000);
}
bootstrap();
NestJS
에는 기본 예외 처리 레이어가 존재한다.
이를 확장해서 사용하기 위해선 BaseExceptionFilter
를 다음과 같이 확장하면 된다.
import { Catch, ArgumentsHost } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
@Catch()
export class AllExceptionsFilter extends BaseExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
super.catch(exception, host);
}
}
이때 생성자로 AbstractHttpAdapter
를 넘겨줘야하므로 다음과 같이 설정한다.
import { HttpAdapterHost, NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './common/exception/all-exception.filter';
import { HttpExceptionFilter } from './common/exception/http-exception.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const { httpAdapter } = app.get(HttpAdapterHost);
app.useGlobalFilters(
new HttpExceptionFilter(),
// new AllExceptionsFilter(httpAdapter),
new AllExceptionsFilter2(httpAdapter),
);
await app.listen(3000);
}
bootstrap();