Nest는 애플리케이션 전체에서 처리되지 않은 모든 예외를 처리하는 기본 제공 예외 레이어와 함께 제공됩니다. 응용 프로그램 코드에서 예외를 처리하지 않으면 이 계층에서 예외를 포착하여 적절한 사용자 친화적인 응답을 자동으로 보냅니다.
먼저 컨트롤러에서 exception을 만들어 보도록 하겠습니다.
import { CatsService } from './cats.service';
import {
Controller,
Get,
Patch,
Post,
Put,
Delete,
HttpException,
} from '@nestjs/common';
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
// cats/
@Get()
getAllCat() {
throw new HttpException('api http exception', 401); // exception 생성
return 'all cats';
}
// cats/:id
@Get(':id')
getOneCat() {
return 'one cat';
}
@Post()
createCat() {
return 'create cat';
}
@Put(':id')
updateCat() {
return 'update cate';
}
@Patch(':id')
updatePartialCat() {
return ' update';
}
@Delete(':id')
deleteCat() {
return 'delete service';
}
}
getAllCat을 호출하면 exception을 던집니다. 첫번째 인자로는 에러 메시지, 두번째 인자로는 statusCode를 넣으면 됩니다. postman으로 호출해도보록 하겠습니다.
설정한 메시지와 에러코드를 반환하는 것을 확인할 수 있습니다. 이렇게 Nest가 제공해주는 방식으로 에러를 반환할 수 있겠지만 서비스에 형태에 따라서 에러를 핸들링을 할 때 커스텀이 필요한 경우가 있습니다.
공식 홈페이지에 그 방법이 잘 정리되어 있습니다.
링크텍스트
간단하게 커스텀을 해보도록 하겠습니다.
@Get()
getAllCat() {
throw new HttpException(
{ success: false, msg: 'api is have problem' },
HttpStatus.UNAUTHORIZED,
);
return 'all cats';
}
이렇게 간단하게 exception을 커스텀 할 수 있습니다. 하지만 아쉬운 점은 코드의 중복이 일어날 수 있다는 점입니다.
exceptionfilter class를 만들어서 한번에 핸들링 할 수 있습니다.
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,
});
}
}
exceptionFilter class를 만들었습니다. 당연하게 exceptionFilterClass를 만든다고 filter가 적용되지 않습니다. filter를 적용 해보도록 하겠습니다.
첫번째 방법은 컨트롤러의 function에 직접적으로 filter를 적용하는 방법입니다.
@Get()
@UseFilters(HttpExceptionFilter)
getAllCat() {
throw new HttpException('api have problem', HttpStatus.UNAUTHORIZED);
return 'all cats';
}
잘 적용이 된 것을 확인할 수 있습니다.
해당 컨트롤러 클래스 전역에 필터를 적용하고 싶다면 클래스 위에 추가해주면 됩니다.
@Controller('cats')
@UseFilters(HttpExceptionFilter)
export class CatsController {
constructor(private readonly catsService: CatsService) {}
// ... 생략
전역 필터로 적용시켜 보도록 하겠습니다.
main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './http-exception.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(8000);
}
bootstrap();
404 에러를 발생시켜보도록 하겠습니다.
filter가 전역으로 잘 적용된 것을 확인할 수 있습니다. response가 전의 format과 다른 것을 볼 수 있습니다. HttpExceptionFilter의 response를 변경했기 때문입니다.
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();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
error,
});
}
}
해당 게시글은 "NestJS 공식 홈페이지"와
인프런 강의 "탄탄한 백엔드 NestJS, 기초부터 심화까지(윤상석)"을 참고하여 만들었습니다.