Exception Filter는 로직처리가 되고 진행이 됩니다. 그 후에는 interceptor로 이동하게 됩니다. 즉 interceptor에서도 Exception Filter를 핸들링 할 수 있다는 의미입니다.
Exception Filter는 예외를 필터링 하는 것입니다. 보통 Exception Filter가 유용한 경우는 에러가 생겼을 때 로그를 남기거나 모니터링에 이러한 문제점이 발생한다 라고 알려주기 위해서 사용될 때 의미가 좋습니다.
사진으로 알 수 있듯, Filter는 Client Side에 가깝고, Server 쪽이랑은 먼 것을 알 수 있습니다.
Built-in HTTP exceptions#
Nest provides a set of standard exceptions that inherit from the base HttpException
. These are exposed from the @nestjs/common package, and represent many of the most common HTTP exceptions:
BadRequestException
UnauthorizedException
NotFoundException
ForbiddenException
NotAcceptableException
RequestTimeoutException
ConflictException
GoneException
HttpVersionNotSupportedException
PayloadTooLargeException
UnsupportedMediaTypeException
UnprocessableEntityException
InternalServerErrorException
NotImplementedException
ImATeapotException
MethodNotAllowedException
BadGatewayException
ServiceUnavailableException
GatewayTimeoutException
PreconditionFailedException
여기서 주목해야하는 것은 HttpException
입니다. Exception 목록들은 전부 HttpException
를 상속받은 것입니다. 추후에 Exception Filter 클래스를 만들 때, HttpException
에 해당하는 Exception만 잡는 코드를 작성할 것입니다.
본격적으로 코드를 작성하고 적용을 해보겠습니다.
import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from "@nestjs/common";
@Catch(HttpException) // HttpException에 해당하는 모든 예외를 자는다.
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const context = host.switchToHttp();
const response = context.getResponse();
const request = context.getRequest();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
message: exception.message,
timestamp: new Date().toLocaleString('kr'),
path: request.url, // 어떤 url에서 에러 발생 했는지 알 수 있음
});
}
}
@Get()
@UseInterceptors(LogInterceptor)
@UseFilters(HttpExceptionFilter)
getPosts(
@Query() query: PaginatePostDto,
) {
throw new BadRequestException('에러 테스트');
return this.postsService.paginatePosts(query);
}
포스트맨으로 테스트를 하겠습니다.
{
"message": "에러 테스트",
"error": "Bad Request",
"statusCode": 400
}
.
.
차이비교
.
.
{
"statusCode": 400,
"message": "에러 테스트",
"timestamp": "2024. 2. 16. 오전 7:31:22",
"path": "/posts?order__createdAt=DESC&take=2"
}
Exception Filter 코드의 경우 보통 중간 부분에 로그를 저장하거나 외부 모니터링 시스템이 API를 콜 하는 코드를 작성합니다. 그리고 이 Exception Filter를 전역적으로 적용하기 위해서 main.ts에 적용을 합니다.
import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from "@nestjs/common";
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const context = host.switchToHttp();
const response = context.getResponse();
const request = context.getRequest();
const status = exception.getStatus();
// 로그 파일을 생성하거나
// 에러 모니터링 시스템에 API 콜 하기
response
.status(status)
.json({
statusCode: status,
message: exception.message,
timestamp: new Date().toLocaleString('kr'),
path: request.url,
});
}
}
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { HttpExceptionFilter } from './common/exception-filter/http-exception-filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({
transform: true,
transformOptions: {
enableImplicitConversion: true
},
whitelist: true,
forbidNonWhitelisted: true,
}));
app.useGlobalFilters(new HttpExceptionFilter()); // Exception Filter 전역 적용
await app.listen(3000);
}
bootstrap();
하지만 지금은 사용하지 않으니 main.ts와 컨트롤러에서 강제로 에러를 던진 코드와 @UseFilter를 전부 지우겠습니다.