Nest는 프레임워크 내에 예외 레이어를 두고 있음 애플리케이션을 통틀어 제대로 처리하지 못한 예외를 처리하는 역할
예외 처리기를 통해 유저가 이해하기 쉬운 형태로 변환하여 전송
InternalServerErrorException
internalServerErrorException의 선언ㅇ부에서 HttpException을 상속받고있음 HttpException은 다시 자바스크립트의 Error를상속함
모든 예외는 Error객체로 부터 파생
import { HttpException } from './http.exception';
/**
* Defines an HTTP exception for *Internal Server Error* type errors.
*
* @see [Built-in HTTP exceptions](https://docs.nestjs.com/exception-filters#built-in-http-exceptions)
*
* @publicApi
*/
//HttpException을 상속 받고있음
export declare class InternalServerErrorException extends HttpException {
/**
* Instantiate an `InternalServerErrorException` Exception.
*
* @example
* `throw new InternalServerErrorException()`
*
* @usageNotes
* The HTTP response status code will be 500.
* - The `objectOrError` argument defines the JSON response body or the message string.
* - The `description` argument contains a short description of the HTTP error.
*
* By default, the JSON response body contains two properties:
* - `statusCode`: this will be the value 500.
* - `message`: the string `'Internal Server Error'` 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 description a short description of the HTTP error.
*/
constructor(objectOrError?: string | object | any, description?: string);
}
HttpException
생성자는 response, status 두개의 인수를 전달받음
response:JSON 응답의 본문, 문자열이나 Record<string, any> 타입의 객체를 전달할 수 있음
status: 에러의 속성을 나타내는 HTTP 상태코드
JSON 응답의 본문은 statusCode와 message 속성을 기본으로 가짐
/**
* Defines the base Nest HTTP exception, which is handled by the default
* Exceptions Handler.
*
* @see [Built-in HTTP exceptions](https://docs.nestjs.com/exception-filters#built-in-http-exceptions)
*
* @publicApi
*/
export declare class HttpException extends Error {
private readonly response;
private readonly status;
/**
* Instantiate a plain HTTP Exception.
*
* @example
* `throw new HttpException()`
*
* @usageNotes
* The constructor arguments define the response and the HTTP response status code.
* - The `response` argument (required) defines the JSON response body.
* - The `status` argument (required) defines the HTTP Status Code.
*
* By default, the JSON response body contains two properties:
* - `statusCode`: the Http Status Code.
* - `message`: a short description of the HTTP error by default; override this
* by supplying a string in the `response` parameter.
*
* To override the entire JSON response body, pass an object to the `createBody`
* method. Nest will serialize the object and return it as the JSON response body.
*
* The `status` argument is required, and should be a valid HTTP status code.
* Best practice is to use the `HttpStatus` enum imported from `nestjs/common`.
*
* @param response string or object describing the error condition.
* @param status HTTP response status code.
*/
constructor(response: string | Record<string, any>, status: number);
cause: Error | undefined;
/**
* Configures error chaining support
*
* See:
* - https://nodejs.org/en/blog/release/v16.9.0/#error-cause
* - https://github.com/microsoft/TypeScript/issues/45167
*/
initCause(): void;
initMessage(): void;
initName(): void;
getResponse(): string | object;
getStatus(): number;
static createBody(objectOrError: object | string, description?: string, statusCode?: number): object;
}
app.controller.ts
http://localhost:3000/error 경로로 요청 전송시 foo가 undefined이기 때문에 에러방생
서버가 예상하지 못한 에러를 처리할때 500 "Internal Server Error" 반환
import { Controller, Get, InternalServerErrorException } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
@Get('/error')
//foo가 undefined이기 때문에 에러 발생
error(foo: any): string {
//
// {
// "statusCode": 500,
// "message": "Internal Server Error"
// }
return foo.bar();
}
}
Users.controller.ts
http://localhost:3000/users/0 요청 전송시 예외처리를 설정한 응답 발생
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
BadRequestException,
HttpException,
HttpStatus,
UseFilters,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { HttpExceptionFilter } from 'src/http-exception.filter';
@Controller('users')
//특정 컨트롤러에만 예외 필터 적용
// @UseFilters(HttpExceptionFilter)
export class UsersController {
constructor(private readonly usersService: UsersService) {}
//특정 엔드포인트에만 예외 필터적용
// @UseFilters(HttpExceptionFilter)
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
if (+id < 1) {
// 1. 단순 문자열
// throw new BadRequestException('id는 0보다 큰 정수여야 합니다');
// 2. HttpException
// throw new HttpException(
// {
// errorMessage: 'id는 0보다 큰 정수여야 합니다',
// foo: 'bar'
// },
// HttpStatus.BAD_REQUEST
// );
// 3. 기본 제공 예외에 description을 함께 전달
throw new BadRequestException(
'id는 0보다 큰 정수여야 합니다',
'id format exception',
);
}
return this.usersService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(+id, updateUserDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.usersService.remove(+id);
}
}
응답결과
예외 필터
Nest에서 제공하는 전역 예외 필터외에 직업 예외 필터 레이어를 두어 원하는 대로 예외를 다룰 수 있음
로그를 남기거나 응답객체를 원하는 대로 변경할떄 사용
HttpExceptionFilter
Catch 데커레이터는 처리되지 않은 모든 예외를 잡으려고 할 때 사용
예외의 대부분은 Nest에서 HttpExcepion이 아닌 예외는 알 수 없는 에러이므로 InternalServerErrorException으로 처리
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
InternalServerErrorException,
Logger,
} from '@nestjs/common';
import { Request, Response } from 'express';
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
constructor(private logger: Logger) {}
catch(exception: Error, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const res = ctx.getResponse<Response>();
const req = ctx.getRequest<Request>();
//콜스택 변수에 할당
const stack = exception.stack;
if (!(exception instanceof HttpException)) {
exception = new InternalServerErrorException();
}
const response = (exception as HttpException).getResponse();
const log = {
timestamp: new Date(),
url: req.url,
response,
//에러 로그에 콜스택 추가 디버깅
stack,
};
this.logger.log(log);
res.status((exception as HttpException).getStatus()).json(response);
}
}