[nestjs] restapi + prisma 04

in kr •  last year 

이전 글

PART3

오류처리, NestJS 애플리케이션에서 오류 처리를 수행하는 방법을 배웁니다.

NotFoundException 오류 추가하기

조회 후 결과가 없으면 NotFoundException 오류를 발생시켜 가독성을 높입니다.
조회 결과를 받은 후 처리를 해야 되기 때문에 async 를 넣어 결과값 반환을 기다립니다.

// src/articles/articles.controller.ts

import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  NotFoundException,
} from '@nestjs/common';

  @Get(':id')
  @ApiOkResponse({ type: ArticleEntity })


  async findOne(@Param('id') id: string) {
    const article = await this.articlesService.findOne(+id);
    if (!article) {
      throw new NotFoundException(`Article with ${id} does not exist.`);
    }
    return article;
  }

오류처리 전용 레이어 ( dedicated expception layer )

많은 오류 처리 코드로 핵심 응용 프로그램 논리를 복잡하게 만듭니다.

많은 엔드포인트에서 찾을 수 없는 리소스와 같은 유사한 오류를 처리하며, 또한 여러 위치에서 동일한 오류 처리 코드를 복제해야 합니다.

오류 처리 논리가 여러 위치에 흩어져 있기 때문에 오류 처리 논리를 변경하기 어려울 것입니다.

이러한 문제를 해결하기 위해 NestJS에는 애플리케이션 전체에서 처리되지 않은 예외 처리를 담당하는 예외 레이어가 있습니다.

NestJS에서는 애플리케이션 내부에서 발생한 다양한 종류의 예외를 처리하는 방법을 정의하는 예외 필터를 만들 수 있습니다.

nestjs 전역 오류 처리 필터

현재 프로젝트의 경우 동일 제목으로 Article 을 생성하면, 첫번째는 생성하는데 문제 없으나, 2번째에는 동일한 제목을 등록하면 오류가 발생합니다.

terminal 에서 확인해보면, 아래와 같이 (제목이 unique 로 지정되어 있기 때문) 500, 내부서버 오류 (Internal Server Error) 가 발생합니다.

사용자 오류 필터 만들기

npx nest generate filter prisma-client-exception

위 커맨드 실행 이후 아래와 같이 파일을 수정합니다.

아래 필터가 PrismaClientKnownRequestError 오류를 처리 할 수 있도록 @Catch 데코레이터를 사용합니다.

// src/prisma-client-exception.filter.ts

import { ArgumentsHost, Catch } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
import { Prisma } from '@prisma/client';

@Catch(Prisma.PrismaClientKnownRequestError) // 1
export class PrismaClientExceptionFilter extends BaseExceptionFilter {
  // 2
  catch(exception: Prisma.PrismaClientKnownRequestError, host: ArgumentsHost) {
    console.error(exception.message); // 3

    // default 500 error code
    super.catch(exception, host);
  }
}

여기서 특정 프리즈마 상태코드에 따른 동작 처리를 제어하고 싶은 경우 아래와 같이 작성 합니다.

//src/prisma-client-exception.filter.ts

import { ArgumentsHost, Catch, HttpStatus } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
import { Prisma } from '@prisma/client';
import { Response } from 'express';

@Catch(Prisma.PrismaClientKnownRequestError)
export class PrismaClientExceptionFilter extends BaseExceptionFilter {
  catch(exception: Prisma.PrismaClientKnownRequestError, host: ArgumentsHost) {
    console.error(exception.message);
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const message = exception.message.replace(/\n/g, '');

    switch (exception.code) {
      case 'P2002': {
        const status = HttpStatus.CONFLICT;
        response.status(status).json({
          statusCode: status,
          message: message,
        });
        break;
      }
      default:
        // default 500 error code
        super.catch(exception, host);
        break;
    }
  }
}

필터 적용하기

위에서 만든 필터를 적용하기 위해 main.ts 파일을 수정합니다.

// src/main.ts

import { HttpAdapterHost, NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { PrismaClientExceptionFilter } from './prisma-client-exception.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const config = new DocumentBuilder()
    .setTitle('Median')
    .setDescription('The Median API description')
    .setVersion('0.1')
    .build();

  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api', app, document);

  const { httpAdapter } = app.get(HttpAdapterHost);
  app.useGlobalFilters(new PrismaClientExceptionFilter(httpAdapter));

  await app.listen(3000);
}
bootstrap();

위와 같이 반영 후 Article 의 Title을 중복하여 등록 해보면

  • 변경 전 : 500, 내부서버 오류 (Internal Server Error)
  • 변경 후 : 409, 충돌 오류 (Conflict Error)

로 변경되어 오류가 발생합니다. ( Frontend 에서는 오류 메시지를 노출하지 않고, 오류 코드만 전달하여 처리하는 것이 좋습니다.)

PART3 끝

Prisma 오류를 처리하는 방법을 배웠습니다.

그러나 기술 자체는 Prisma에만 국한되지 않습니다. 이를 사용하여 애플리케이션의 모든 유형의 오류를 처리할 수 있습니다.

참조링크

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.

image.png

Upvoted! Thank you for supporting witness @jswit.