NestJS 프레임워크 사용을 위한 기본 개념에 대해 간략하게 정리해 보고자 한다.
본 포스팅에서는 exception filter를 사용하는 방법에 대해 알아보도록 하겠다.
< 목차 >
- 예외 처리
- Exception filter
1. 예외 처리
예외 처리(exception handling)란 프로그래머가 예기치 못한 예외의 발생에 미리 대처하는 코드를 작성하는 것으로 이를 통해 실행 중인 프로그램의 비정상적인 종료를 막고 프로그램의 상태를 정상 상태로 유지하는 것이 목적이다.
보통 Node.js에서 에러를 처리할 때는 throw new Error( ) 와 같은 방식을 통해 에러를 발생시켜 예외 처리를 진행하게 된다. NestJS에서는 HttpException( ) 이라는 인터페이스를 제공해주기 때문에 http에 대한 에러는 HttpException( )을 사용해서 처리한다.
@Get()
async findAll() {
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
NestJS 공식문서에서 제공해주는 위의 예제코드와 같이 throw new HttpException( ) 을 사용할 경우, 예외 처리에 대해 다음과 같은 형태로 응답을 받을 수 있다.
{
"statusCode": 403,
"message": "Forbidden"
}
2. Exception filter
NestJS에서 제공해주는 예외 처리 방식을 그대로 사용해도 되지만 커스터마이징을 하고 싶은 경우, Exception filter를 사용해 볼 수 있다. NestJS에서는 exception이 발생한 경우, 재사용성을 고려해서 exception에 관한 처리를 한 곳으로 모은 다음 필터링을 거쳐 원하는 형태의 응답으로 반환해주는 방식을 만들어서 사용할 수 있다.
다음은 NestJS 공식문서에서 제공해주는 http-exception.filter.ts 파일이다.
// http-exception.filter.ts 파일
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,
});
}
}
ctx는 context 즉, 실행 환경을 의미하고 exception.getStatus( ) 메소드를 통해 예외에 해당하는 http 상태코드를 전달 받을 수 있다. 추가로 exception.getResponse( ) 메소드 역시 자주 사용되는데 해당 메소드를 통해 에러 메시지 혹은 NestJS에서 제공하는 에러 객체를 전달 받을 수 있다.
http-exception.filter.ts 파일을 작성 완료하였다면, exception filter를 적용시켜 주기만 하면 되는데, 이 때 @UseFilters( ) 데코레이터를 사용하면 된다.
@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
throw new ForbiddenException();
}
@UseFilters( ) 데코레이터를 사용해서 우리가 만든 HttpExceptionFilter를 인자로 넘겨주도록 하자. @UseFilters( ) 데코레이터가 붙은 함수 안에서 exception이 발생하게 되면 exception에 대한 내용이 데코레이터의 인자값으로 들어간 HttpExceptionFilter로 넘어간 다음 필터링을 거쳐 반환된다.
@UseFilters( ) 데코레이터는 각각의 함수 뿐만 아니라 다음과 같이 컨트롤러 전체에 적용할 수도 있다.
@Controller('cats')
@UseFilters(HttpExceptionFilter)
export class CatsController {}
애플리케이션 전역에서 작용하는 global-scoped filter 를 설정할 수도 있는데, 이를 위해서는 main.ts 파일 안에서 다음과 같이 app.useGlobalFilters( ) 메소드를 사용해 HttpExceptionFilter를 등록해주면 된다.
// main.ts 파일
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './common/exceptions/http-exception.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(4000);
}
bootstrap();
useGlobalFilters( ) 메소드를 통해 애플리케이션 전역에 exception filter를 등록해 사용할 경우, 다음과 같이 HttpExceptionFilter를 만들어서 NestJS 자체적으로 반환해주는 exception 처리 결과의 응답 형태에 대해서도 커스터마이징이 가능하다.
// http-exception.filter.ts 파일
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();
const error = exception.getResponse() as
| string
| { error: string; statusCode: number; message: string | string[] };
if (typeof error === 'string') {
response.status(status).json({
success: false,
timestamp: new Date().toISOString(),
statusCode: status,
path: request.url,
error,
});
} else {
response.status(status).json({
success: false,
timestamp: new Date().toISOString(),
...error,
});
}
}
}
exception.getResponse( ) 메소드를 통해 error 메시지 혹은 error 객체를 반환 받을 수 있는데, error 메시지의 경우 특정 함수 안에서 throw new HttpException( ) 메소드의 인자값으로 전달한 string 값이 오게 되며 error 객체의 경우 NestJS에서 자체적으로 반환하는 예외 처리에 대한 응답 객체이다.
'Node > NestJS' 카테고리의 다른 글
NestJS - MongoDB 연결하기 & 환경 변수 설정 (0) | 2023.04.08 |
---|---|
NestJS - Pipes & Interceptors (0) | 2023.03.26 |
NestJS - LoggerMiddleware 설정 (0) | 2023.03.13 |
NestJS - 캡슐화(Encapsulation) & Modules (0) | 2023.03.10 |
NestJS - 의존성 주입(DI) & Providers (0) | 2023.03.10 |