NestJS-Exception filter

jaegeunsong97·2024년 2월 15일
0

NestJS

목록 보기
29/37
post-custom-banner

🖊️이론

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만 잡는 코드를 작성할 것입니다.


🖊️HttpExceptionFilter

본격적으로 코드를 작성하고 적용을 해보겠습니다.

  • common/exception-filter/http-exception-filter.ts
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에서 에러 발생 했는지 알 수 있음
        });
    }
}
  • posts.controller.ts
@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에 적용을 합니다.

  • common/exception-filter/http-exception-filter.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,
        });
    }
}
  • main.ts
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를 전부 지우겠습니다.

profile
블로그 이전 : https://medium.com/@jaegeunsong97
post-custom-banner

0개의 댓글