NestJS 마스터 시리즈 9화. 예외 처리 전략 – 오류는 숨기지 말고 설계하라
“서비스 품질은 에러 메시지를 보면 알 수 있다”
NestJS에서 예외 처리 시스템을 구조적으로 설계하는 방법을 다룹니다. HTTP 예외, ExceptionFilter, 커스텀 예외 클래스까지 실무 중심으로 예외 설계 전략을 소개합니다.
에러를 숨기는 백엔드는 신뢰할 수 없다
현업에서 발생하는 많은 장애는, 에러 그 자체보다 에러가 제대로 처리되지 않은 결과에서 시작된다.
NestJS는 @nestjs/common 모듈에 예외 처리 시스템을 내장하고 있으며, 이를 통해 통일된 에러 응답과 로깅 전략을 설계할 수 있다.
기본 예외 – HttpException 사용하기
NestJS는 HttpException 클래스를 통해 명시적인 에러 응답을 만들 수 있다.
import { HttpException, HttpStatus } from '@nestjs/common';
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
또는 객체 형태로 세부 메시지를 전달할 수 있다.
throw new HttpException(
{
status: HttpStatus.FORBIDDEN,
error: 'You are not allowed to access this resource',
},
HttpStatus.FORBIDDEN,
);
커스텀 예외 클래스 만들기
자주 사용하는 예외는 클래스로 분리하면 가독성과 재사용성이 높아진다.
import { HttpException, HttpStatus } from '@nestjs/common';
export class UserNotFoundException extends HttpException {
constructor(userId: string) {
super(`User with ID ${userId} not found`, HttpStatus.NOT_FOUND);
}
}
사용 예시:
if (!user) {
throw new UserNotFoundException(id);
}
전역 예외 처리기 – ExceptionFilter
NestJS는 @Catch() 데코레이터를 사용한 예외 필터 시스템을 통해, 전역 또는 특정 예외에 대해 커스텀 응답 처리를 구현할 수 있다.
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
} from '@nestjs/common';
@Catch(HttpException)
export class HttpErrorFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const status = exception.getStatus();
const message = exception.getResponse();
response.status(status).json({
statusCode: status,
message,
timestamp: new Date().toISOString(),
});
}
}
main.ts에서 전역 등록:
app.useGlobalFilters(new HttpErrorFilter());
비HTTP 예외도 처리 가능
NestJS는 @Catch()의 인자로 HTTP 외의 예외도 필터링할 수 있다.
@Catch(TypeError, QueryFailedError)
- DB 예외, 타입 예외 등 다양한 상황에 맞는 전용 필터 구성 가능
로깅과 에러 응답을 분리하라
서비스가 성숙해질수록 에러 로깅과 클라이언트 응답은 분리되어야 한다.
- 내부에는 스택 트레이스 포함한 상세 로그 저장
- 외부에는 간결한 메시지와 statusCode만 전달
이런 전략은 Logger와 ExceptionFilter를 함께 사용하는 것으로 실현할 수 있다.
실무 적용 전략
전략내용
공통 예외 메시지 포맷 정의 | statusCode, message, timestamp 등 일관된 구조 |
커스텀 예외 클래스 분리 | 도메인별로 예외 클래스를 정의해 로직과 구분 |
ExceptionFilter 계층화 | HTTP 예외, DB 예외, 권한 예외 등 역할 분리 |
로깅 연계 | Sentry, Logstash 등과 연동해 실시간 모니터링 구현 |
마무리 인사이트
NestJS는 예외 처리조차 설계 가능한 아키텍처 요소로 다룰 수 있도록 도와준다.
그냥 throw하는 것이 아니라, 의도적이고 예측 가능한 실패 흐름을 만들 수 있다는 것이 큰 장점이다.
- 에러는 숨기지 말고, 구조화하라
- 예외 메시지는 팀 내 API 계약의 일부다
- 클라이언트, 백엔드, DevOps가 공유할 수 있는 언어로 설계해야 한다
좋은 서비스는 성공보다 실패를 잘 다루는 구조에서 시작된다
다음 회차 예고
NestJS 마스터 시리즈 10화. 미들웨어와 인터셉터 – 요청 흐름을 설계하는 법
요청 전/후 흐름 제어, 로깅, 인증, 응답 가공을 구조화하는 방법을 설명합니다.