체인의정석

Nest.js 수정사항 총 정리 01 ) 예외처리 패턴 - Internal Server Error 리팩토링 본문

개발/backend

Nest.js 수정사항 총 정리 01 ) 예외처리 패턴 - Internal Server Error 리팩토링

체인의정석 2021. 12. 7. 18:39
728x90
반응형

1. 공통 예외처리 부분

에러 처리의 경우 결과적으로 invalid input과 internal server error로 나뉘었다. 여기에 대한 구조는 다음과 같다.

  @Get('/:ethAddress/경로')
  async 함수이름(
    @Param('ethAddress') ethAddress: string,
    .
    .
    .
    @Query('page') page?: number,
  ): Promise<함수에대한Response | CommonErrorResponse> { //오류의 경우 공통 부분으로 빼두어서 관리
    const 객체화된요청 = new RelatedTransactionsRequest(
      ethAddress,
      new Date(fromDate),
      .
      .
      page * 1,
    );
    const errors = await validate(객체화된요청); //쿼리 파라미터가 있는 경우 validate pipeline을 사용할 수 없으므로 validate 함수를 사용 만약 쿠키나 키같은게 들어갈 시에는 2단계가 한번 더 잡아주는 raw request와 command로 한단계를 더 마련해줘야함
    if (errors.length > 0) { //오류가 발생할 경우
      this.logger.error(getConstraintsMessage(errors)); //먼저 logger를 남김 로거에 에러 분석에 필요한 정보를 담음
      const errorValue: string[] = []; //에러에 대한 값 처리
      errors.forEach((x) => {
        errorValue.push(x.value);
      });
      return invalidInputError(errors);// 에러에 대한 반환값은 처리하며, 여기에 중요정보는 담지 않음 잘못된 값과 enum 타입의 정형화된 에러 유형만 표시하여 리턴
    } else {
      const pagingGetAdddressRealtedTxRequest = paginationSet(
        getAdddressRealtedTxRequest,
      );	// 오류가 발생하지 않을 경우 페이지네이션에 대한 기본값 설정해주기
      const response = await this.addressesService.relatedTransactions(
        pagingGetAdddressRealtedTxRequest,
      );	//오류가 발생하지 않을 경우 쿼리 실행
      return response; //결과값 리턴
    }
  }

모든 예외에 대한 처리를 잡아주는것이 포인트이며, 값이 없는 경우 초기화를 해주는 작업이 필요하다. 

또한 오류를 리턴할때 모든 내용을 리턴할 수 없기 때문에 로거를 이용한 에러로그로 자세한 오류메세지를 백엔드에서만 작업해주고 프론트엔드로 넘기는 데이터는 한정적인 데이터만 넘겨주도록 한다.

 

2. 반복되는 예외처리에 대한 공통 모듈 생성

export enum RESPONSE_CODE {
  SUCCESS = 200,
  INVALID_INPUT = 400,
  INTERNAL_SERVER_ERROR = 500,
}

export enum RESPONSE_MESSAGE {
  INVALID_INPUT = 'Invalid Input.',
  INTERNAL_SERVER_ERROR = 'unkown server error has occured',
}

다음과 같이 기본적으로 주는 코드와 에러 메세지를 정해준다. 이를 이용하여 반복되는 코드를 1차적으로 줄인다.

export const internalServerError = () => {
  const code = RESPONSE_CODE.INTERNAL_SERVER_ERROR;
  const message = RESPONSE_MESSAGE.INTERNAL_SERVER_ERROR;
  return new CommonErrorResponse(code, message);
};

export const invalidInputError = (errors) => {
  const code = RESPONSE_CODE.INVALID_INPUT;
  const messege = RESPONSE_MESSAGE.INVALID_INPUT;
  const errorValue: string[] = [];
  errors.forEach((x) => {
    errorValue.push(x.value);
  });
  const response = new CommonErrorResponse(code, messege);
  response.errorValue = errorValue;
  return response;
};

위에서 정의한 코드를 이용하여 반복적으로 나오는 예외처리 부분을 함수로 묶어 준다. 

 

해당 파일은 common의 util 또는 helper등으로 네이밍 한다.

이렇게하면 아래 3번과 같이 코드를 단축시킬 수 있다.

 

3. controller 와 service에 나온 에러들을 위의 공통 모듈을 사용하여 많이 줄일 수 있다.

try { //중략
  return response
} catch(error) {
	this.logger.error(getConstraintsMessage(error));
	return internalServerError();
}

다음과 같이 try 구문에서는 함수가 성공하였을 때의 경우 catch에서 에러가 발생할 경우 처리하는 부분을 catch로 잡아준다.

모든 예외 상황을 가정하고 에러를 잡아주기 때문에 예외 처리는 다중으로 들어가게 되고 코드가 복잡해져서 예외처리에 들어가는 코드를 최대한 줄여야 한다.

 

위에서 로거를 남길때는 에러에 대한 내용을 반복을 통해 모두 처리해주고,  (여기에 대한 모듈은 직접 작성한 코드가 아니여서 비공개로 정리해 두었다.)

에러를 리턴해준다. 

에러를 리턴할때 리턴을 함수에서 해주더라도 변수로 지정한 화살표 함수를 만든것이므로 return을 상위 레벨에서 한번 해주어야 리턴이 제대로 작동한다.

 

위의 내용은 서버 내부의 에러이고 valdation 체크를 하는 부분은 따로 처리하였다.

728x90
반응형
Comments