[TIL/Nest] 2025/04/21
Authentication과 Authorization에 대한 이해가 깊어짐에 따라, NestJS에서의 예외 처리에 대한 고민이 생겼습니다. 이번 글에서는 NestJS에서 예외를 어떻게 처리하는지 정리해보겠습니다.NestJS는 HttpException이라는 기본 예외 클
1. Overview ✍️
Authentication과 Authorization에 대한 이해가 깊어짐에 따라, NestJS에서의 예외 처리에 대한 고민이 생겼습니다. 이번 글에서는 NestJS에서 예외를 어떻게 처리하는지 정리해보겠습니다.
2. Throwing standard exceptions ✍️

NestJS는 HttpException이라는 기본 예외 클래스를 제공하여 에러를 HTTP 형식으로 처리할 수 있도록 돕습니다. 해당 클래스는 @nestjs/common 패키지에 포함되어 있습니다. API 요청 중 오류가 발생하면 HttpException을 사용하여 클라이언트에게 상세한 오류 메시지를 제공할 수 있습니다.
다음은 GET 요청에 대해 예외를 던지는 예시입니다:
@Get()
async findAll() {
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}여기서 첫 번째 인자인 Forbidden은 클라이언트에게 전달될 에러 메시지이고, 두 번째 인자인 HttpStatus.FORBIDDEN은 HTTP 상태 코드를 나타냅니다.
클라이언트의 응답은 다음과 같습니다:
{
"statusCode": 403,
"message": "Forbidden"
}에러 메시지만 변경하고 싶다면 첫 번째 인자를 다른 문자열로 변경하면 됩니다. 만약 전체 응답 본문을 변경하고 싶다면, 객체를 전달할 수도 있습니다:
@Get()
async findAll() {
try {
await this.service.findAll();
} catch (error) {
throw new HttpException({
status: HttpStatus.FORBIDDEN,
error: 'This is a custom message',
}, HttpStatus.FORBIDDEN, {
cause: error
});
}
}변경된 응답은 다음과 같습니다:
{
"status": 403,
"error": "This is a custom message"
}3. Exceptions logging ✍️
NestJS는 기본적으로 HttpException과 같은 예외를 콘솔에 출력하지 않습니다. 이는 이러한 예외가 애플리케이션 흐름의 일부로 간주되기 때문입니다.
하지만 개발 중에 예외도 콘솔에 출력하고 싶다면, ExceptionFilter를 커스터마이징하여 로깅할 수 있습니다. 이 부분은 추후에 더 다루겠습니다.
또한, 사용자 정의 예외 클래스를 만들어서 예외를 더 명확하게 구분하고 재사용성을 높이는 것도 좋은 방법입니다.
4. Custom exceptions ✍️
NestJS는 기본 HttpException 클래스를 제공하지만, 프로젝트의 상황에 맞춰 의미 있는 이름을 가진 사용자 정의 예외 클래스를 만들 수 있습니다. 예를 들어, 접근이 금지된 경우를 명시적으로 처리하려면 ForbiddenException을 만들 수 있습니다:
export class ForbiddenException extends HttpException {
constructor() {
super('Forbidden', HttpStatus.FORBIDDEN);
}
}이제 이 사용자 정의 예외는 다음과 같이 사용할 수 있습니다:
@Get()
async findAll() {
throw new ForbiddenException();
}5. Built-in HTTP exceptions ✍️

NestJS는 기본 HttpException을 상속하는 여러 내장 예외 클래스를 제공합니다. 이러한 예외 클래스들은, 자주 발생하는 HTTP 오류 상황을 다루기 위해 만들어졌습니다. 예외 처리 시 필요에 따라 적절한 클래스를 활용할 수 있습니다.
옵션 파라미터를 사용하여 오류의 원인과 설명을 추가할 수 있습니다:
throw new BadRequestException('Something bad happened', {
cause: new Error(),
description: 'Some error description',
});응답은 다음과 같습니다:
{
"message": "Something bad happened",
"error": "Some error description",
"statusCode": 400
}6. Exception filters ✍️
예외 필터는 기본 예외 처리 방식으로 처리하기 어려운 특별한 예외를 다루기 위해 사용됩니다. 예를 들어, 에러가 발생했을 때 단순히 에러 코드만 보내는 대신, 추가적인 정보를 남기거나 로그를 기록하고 싶을 때 사용할 수 있습니다.
다음은 HttpException 타입의 예외만을 처리하는 예외 필터 예시입니다:
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,
});
}
}7. Arguments Host ✍️
catch() 메서드의 매개변수인 exception과 host를 살펴보겠습니다.
1. exception: 현재 처리 중인 예외 객체입니다. HttpException 타입이므로, 상태 코드와 메시지를 포함한 예외 정보를 가져올 수 있습니다.
2. host: ArgumentsHost 객체로, NestJS에서 제공하는 객체로 다양한 실행 컨텍스트의 인수에 접근할 수 있습니다. 예외 필터에서 ArgumentsHost를 사용하면 HTTP 요청/응답 객체를 손쉽게 다룰 수 있습니다. 주요 메서드로는 switchToHttp()가 있으며, 이를 통해 HTTP 요청/응답 객체에 접근할 수 있습니다.
8. Binding filters ✍️
@UseFilters() 데코레이터를 사용하면 예외 필터를 특정 컨트롤러나 메서드에 바인딩할 수 있습니다. 예를 들어, HttpExceptionFilter를 다음과 같이 사용할 수 있습니다:
@Post()
@UseFilters(new HttpExceptionFilter())
async create(@Body() createCatDto: CreateCatDto) {
throw new ForbiddenException();
}인스턴스 대신 클래스에 필터를 적용하는 것이 좋습니다. 이렇게 하면 필터를 전역적으로 재사용할 수 있어 메모리 효율성을 높일 수 있습니다:
@Controller()
@UseFilters(new HttpExceptionFilter())
export class CatsController {}전역 필터를 적용하려면 useGlobalFilters() 메서드를 사용하면 됩니다:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();전역 필터는 애플리케이션의 모든 컨트롤러와 라우트 핸들러에서 사용됩니다.
9. Catch everything ✍️
모든 예외를 처리하려면 @Catch() 데코레이터의 매개변수를 비워두면 됩니다. 이렇게 하면 HttpException 외의 예외도 처리할 수 있습니다:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
@Catch()
export class CatchEverythingFilter implements ExceptionFilter {
constructor(private readonly httpAdapterHost: HttpAdapterHost) {}
catch(exception: unknown, host: ArgumentsHost): void {
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);
}
}10. Inheritance ✍️
애플리케이션 요구사항을 충족시키기 위해 맞춤화된 예외 필터를 생성할 수 있지만, 기본 제공되는 예외 필터를 확장하여 사용하는 방법도 있습니다. 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);
}
}전역 필터로 확장하려면 HttpAdapter 참조를 주입하거나 APP_FILTER를 사용하여 필터를 설정할 수 있습니다:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const { httpAdapter } = app.get(HttpAdapterHost);
app.useGlobalFilters(new AllExceptionsFilter(httpAdapter));
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
@Module({
providers: [
{
provide: APP_FILTER,
useClass: HttpExceptionFilter,
},
],
})
export class AppModule {}11. Conclusion ✍️
NestJS에서의 예외 처리는 단순한 오류 메시지 전달을 넘어, 응답 일관성 유지와 로깅, 디버깅 효율성까지 책임지는 중요한 설계 포인트입니다.
단순한 에러 응답은 HttpException과 내장 예외 클래스 (BadRequestException, ForbiddenException 등)로 처리할 수 있고, 보다 구체적인 상황에서는 커스텀 예외 클래스를 만들어 재사용성과 가독성을 높일 수 있습니다. 복잡한 예외 흐름을 관리하려면 Exception Filter를 도입하여, 로깅, 포맷팅, 전역 처리 등 다양한 방식으로 예외를 다룰 수 있습니다.
NestJS는 예외를 ‘흐름 제어’의 한 형태로 보고 있으며, 필터나 상속을 통해 유연하게 커스터마이징할 수 있도록 설계되어 있습니다. 따라서, 예외 처리는 단순히 try-catch에 머무르지 않고, 애플리케이션 전반의 안정성과 UX를 향상시키는 도구로 활용되어야 할 것입니다.
reference: https://docs.nestjs.com/exception-filters#binding-filters
More to read
Amazon VPC Architecture 이해하기
새로운 프로젝트를 기획하며, 개발에서 무엇을 가장 먼저 고민해야 하는지 다시 돌아보게 되었습니다.한때는 프론트엔드가 모든 설계의 출발점이라고 믿었습니다. 유저가 무엇을 보고, 어떤 흐름에서 머무르고 이탈하는지에 대한 이해 없이 서비스를 만든다는 건 불가능하다고 생각했기
'원사이트'프론트엔드 관점으로 알고리즘 이해하기
오랜만에 방법론에 관한 글을 쓰게 되었습니다. 최근 상황은 이렇습니다. SSAFY에서는 하루에 엄청난 양의 알고리즘 문제들을 과제로 수행하게 됩니다. 그 과정에서, '구현력'이 매우 떨어진다는 생각이 들었습니다. 완전히 어려운 문제라면 '아쉬움'이라는 감정조차 느끼지
SubnetVPC 설계의 시작: IP와 Subnet
반복되는 루틴 속에서 얻은 안정감을 발판 삼아, 이제는 기술적 스펙트럼을 넓히기 위한 개인 프로젝트에 착수하고자 합니다.이번 프로젝트의 목표는 단순한 포트폴리오 구축을 넘어, 실제 서비스 수준의 블로그 시스템 구현과 다국어 처리 적용 등 실무에 가까운 역량을 한 단계