[NestJS] Exception filter

이재훈·2023년 5월 29일
0

NestJs

목록 보기
6/8

Exception filter

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를 만들어서 한번에 핸들링 할 수 있습니다.

src/http-exception.filter.ts

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, 기초부터 심화까지(윤상석)"을 참고하여 만들었습니다.

profile
부족함을 인정하고 노력하자

0개의 댓글