nest.js 에서는 내장 global execption filter 를 사용하여 HttpException
을 처리한다.
application code 단에서 handle 되지 않은 예외들은 nest.js 의 내장 exceptions layer
가 인지하고 이를 유저가 이해하기 쉬운 언어의 response 로 전달한다. HttpException
class 나 HttpException
을 상속받아 정의한 class 어느 것에도 정의되어 있지 않은 error 를 마주할 경우엔 내장 exception filter 가 아래 JSON response 를 반환한다.
{
"statusCode": 500,
"message": "Internal server error"
}
이 global exception filter 는 기본적으로 http-errors
library 를 지원하기 때문에 statusCode
와 message
속성을 갖은 exception 들은 위의 InternalServerErrorException
대신 정상적인 exception response 값이 반환될 것이다.
import { HttpException, HttpStatus } from '@nestjs/commmon';
async findAll() {
throw new HttpException('message here', HttpStatus.NOT_FOUND);
}
// execption response
{
"statusCode": 404,
"message": "message here"
}
HttpException
contructor 는 두개의 필수 인자를 갖는다.
string
| object
>HttpStatus
from @nestjs/common
)cause
를 통해서 error 와 관련된 부가적인 정보를 제공또한, JSON response body 는 다음 두개의 default 값을 갖는다.
nest.js 의 코드를 보면 이해가 좀 더 쉽다.
// bad-request.exception.d.ts
export declare class BadRequestException extends HttpException {
/**
* Instantiate a `BadRequestException` Exception.
*
* @example
* `throw new BadRequestException()`
*
* @usageNotes
* The HTTP response status code will be 400.
* - The `objectOrError` argument defines the JSON response body or the message string.
* - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
*
* By default, the JSON response body contains two properties:
* - `statusCode`: this will be the value 400.
* - `message`: the string `'Bad Request'` by default; override this by supplying
* a string in the `objectOrError` parameter.
*
* If the parameter `objectOrError` is a string, the response body will contain an
* additional property, `error`, with a short description of the HTTP error. To override the
* entire JSON response body, pass an object instead. Nest will serialize the object
* and return it as the JSON response body.
*
* @param objectOrError string or object describing the error condition.
* @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
*/
constructor(objectOrError?: string | object | any, descriptionOrOptions?: string | HttpExceptionOptions);
}
throw new BadRequestException('Something bad happened', { cause: new Error(), description: 'Some error description' })
> {
"message": "Something bad happened",
"error": "Some error description",
"statusCode": 400,
}
built-in exception filter 이외에도 전달받는 response 에 날짜 정보를 추가하는 등의 추가적인 처리를 원할 때
exception filter
를 추가하여 구현 할 수 있다.
// global-scope 에 적용
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(HttpExceptionFilter);
await app.listen(3000);
}
bootstrap();
// controller-scope 에 적용
@UseFilters(HttpExceptionFilter)
export class CatsController {}
// method-scope 에 적용
@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
throw new ForbiddenException();
}
@UseFilters(new HttpExceptionFilter()) vs @UseFilters(HttpExceptionFilter)
둘다 사용이 가능하지만, HttpExceptionFilter 와 같이 class 로 전달할 경우
nest 가 전체 module 에서 동일한 class 로 여러개의 instance 를 생성해 사용 할 수 있기 때문에 메모리 사용 측면에서 이점이있다.
http 이외의 error 또한 모두 filter 하려면 아래를 참고하도록 하자
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
constructor(private readonly httpAdapterHost: HttpAdapterHost) {}
catch(exception: unknown, host: ArgumentsHost): void {
// In certain situations `httpAdapter` might not be available in the
// constructor method, thus we should resolve it here.
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);
}
}
[all exception filter] https://docs.nestjs.com/exception-filters#catch-everything
[nestjs Execption filters] https://docs.nestjs.com/exception-filters