Contents

Nestjs Exception / validation

Exception

Nest๋Š” application ๋‚ด์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ๋ฅผ ํ•ธ๋“ค๋งํ•˜๊ธฐ ์œ„ํ•ด exception filter ๋ฅผ ๊ฐ€์ง€๊ณ  ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. default exception filter๋Š” BaseExceptionFilter ์ด๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// nest/packages/core/exceptions/base-exception-filter.ts

export class BaseExceptionFilter<T = any> implements ExceptionFilter<T> {
  // ...
  catch(exception: T, host: ArgumentsHost) {
    // ...
    if (!(exception instanceof HttpException)) {
      return this.handleUnknownError(exception, host, applicationRef);
    }
    const res = exception.getResponse();
    const message = isObject(res)
      ? res
      : {
          statusCode: exception.getStatus(),
          message: res,
        };
    // ...
  }
 
  public handleUnknownError(
    exception: T,
    host: ArgumentsHost,
    applicationRef: AbstractHttpAdapter | HttpServer,
  ) {
    const body = {
      statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
      message: MESSAGES.UNKNOWN_EXCEPTION_MESSAGE,
    };
    // ...
  }
}

nest๋Š” ์šฐ๋ฆฌ๊ฐ€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ HttpException์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด, nest ๋Š” Internal server error๋ฅผ ๋‚ด์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
HttpException ์€ 3๊ฐœ์˜ ์ธ์ž๋ฅผ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • statusCode
  • message : string / Record(json)
  • options

message์— ๊ฐ์ฒด๋ฅผ ๋„˜๊ฒจ์ฃผ์–ด ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค๋ฉด, ์ด๋ฅผ serialize ํ•˜์—ฌ ์–ด๋– ํ•œ format์œผ๋กœ ๋ณ€๊ฒฝ ํ›„ response๋กœ ๋„˜๊ฒจ์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
options ๊ฐ์ฒด์— {cause:error}์™€ ๊ฐ™์ด ๋„˜๊ฒจ ์ค€๋‹ค๋ฉด, ๋กœ๊น… ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Exception Filter Customizing

์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ๋Š” BaseExceptionFilter ๋ฅผ default filter๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, catch() ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์— ์›ํ•˜๋Š” ๋™์ž‘์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import { Catch, ArgumentsHost } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
 
@Catch()
export class ExceptionsLoggerFilter extends BaseExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    console.log('Exception thrown', exception);
    super.catch(exception, host);
  }
}

์—ฌ๊ธฐ์„œ @Catch() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋‚ด๋ถ€์— ํŠน์ •ํ•œ exception๋งŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
BaseExceptionFilter๋ฅผ ์ƒ์†๋ฐ›๊ฒŒ ๋˜๋ฉด catch() ๋ฉ”์„œ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ, ์ด ๋ฉ”์„œ๋“œ์—๋Š” 2๊ฐœ์˜ ์ธ์ž๊ฐ€ ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  • HttpException : ํ˜„์žฌ ์ฒ˜๋ฆฌ ๋˜๋Š” ์˜ˆ์™ธ ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  • AugumentsHost : Excecution context ์™€ ๊ด€๋ จ์žˆ๋Š” ๊ฐ์ฒด์ธ๋ฐ, ์ด์— ๋Œ€ํ•œ ์„ค๋ช…์€ ๊ธธ์–ด์งˆ ๊ฒƒ ๊ฐ™์œผ๋ฏ€๋กœ ๋‹ค์Œ ํฌ์ŠคํŒ…์œผ๋กœ ๋ฏธ๋ฃจ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ filter๋ฅผ customizing ํ•˜๊ณ  ๋‚˜์„œ๋Š”, 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. main.ts์— app.useGlobalFilters ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๋“ฑ๋ก
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16

import { HttpAdapterHost, NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as cookieParser from 'cookie-parser';
import { ExceptionsLoggerFilter } from './utils/exceptionsLogger.filter';
 
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
 
  const { httpAdapter } = app.get(HttpAdapterHost);
  app.useGlobalFilters(new ExceptionsLoggerFilter(httpAdapter));
 
  app.use(cookieParser());
  await app.listen(3000);
}
bootstrap();

2. AppModule ์— inject
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import { Module } from '@nestjs/common';
import { ExceptionsLoggerFilter } from './utils/exceptionsLogger.filter';
import { APP_FILTER } from '@nestjs/core';
 
@Module({
  // ...
  providers: [
    {
      provide: APP_FILTER,
      useClass: ExceptionsLoggerFilter,
    },
  ],
})
export class AppModule {}

3. `@UseFilters` ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉ
1
2
3
4
5
@Get(':id')
@UseFilters(ExceptionsLoggerFilter)
getPostById(@Param('id') id: string) {
  return this.postsService.getPostById(Number(id));
}

Validation