반응형
에러 핸들링(Formmat)을 하게된 배경.

 

스터디에서 NestJS를 공부하고 있다.

 

에러 포맷팅을 한 케이스

{
  "errors": [
    {
      "message": "[10000] - 로그인정보가 잘못되었습니다."
    }
  ],
  "data": null
}

 

 

에러 포맷팅을 하지 않은 케이스

{
  "errors": [
    {
      "message": "Custom Error",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "me"
      ],
      "extensions": {
        "code": "BAD_REQUEST",
        "stacktrace": [
          "CustomError: Custom Error",
          "    at AuthGuard.canActivate (/Users/maverick/Desktop/source/nuber-eats/maverick/nuber-eats-backend/src/auth/auth.guard.ts:20:15)",
          "    at GuardsConsumer.tryActivate (/Users/maverick/Desktop/source/nuber-eats/maverick/nuber-eats-backend/node_modules/@nestjs/core/guards/guards-consumer.js:15:34)",
          "    at canActivateFn (/Users/maverick/Desktop/source/nuber-eats/maverick/nuber-eats-backend/node_modules/@nestjs/core/helpers/external-context-creator.js:155:59)",
          "    at target (/Users/maverick/Desktop/source/nuber-eats/maverick/nuber-eats-backend/node_modules/@nestjs/core/helpers/external-context-creator.js:73:37)",
          "    at Object.me (/Users/maverick/Desktop/source/nuber-eats/maverick/nuber-eats-backend/node_modules/@nestjs/core/helpers/external-proxy.js:9:30)",
          "    at field.resolve (/Users/maverick/Desktop/source/nuber-eats/maverick/nuber-eats-backend/node_modules/@apollo/server/src/utils/schemaInstrumentation.ts:82:22)",
          "    at executeField (/Users/maverick/Desktop/source/nuber-eats/maverick/nuber-eats-backend/node_modules/graphql/execution/execute.js:492:20)",
          "    at executeFields (/Users/maverick/Desktop/source/nuber-eats/maverick/nuber-eats-backend/node_modules/graphql/execution/execute.js:414:22)",
          "    at executeOperation (/Users/maverick/Desktop/source/nuber-eats/maverick/nuber-eats-backend/node_modules/graphql/execution/execute.js:344:14)",
          "    at execute (/Users/maverick/Desktop/source/nuber-eats/maverick/nuber-eats-backend/node_modules/graphql/execution/execute.js:136:20)"
        ],
        "originalError": {
          "ok": false,
          "statusCode": 10000
        }
      }
    }
  ],
  "data": null
}

 

 

에러포맷팅을 하지 않는 경우, GraphQL에서 Exception이 발생한 경우, 클라이언트는 확인할 필요없는 StackTrace같은 정보도 나와서,

보기도 어렵고 클라이언트는 매번 에러작업을 해야하는데 불편함을 겪을 수 있어,

클라이언트도 작업을 편하게 할 수 있도록 포맷팅을 하였다

 

소스작업



/* src/ExceptiomnFormat.ts */

import { GraphQLError } from 'graphql';
import { ErrorDto } from './common/dtos/exception,dto';
import { ErrorCode, ErrorMessageV1 } from './common/types/exception.types';

export const formmatError = (error: GraphQLError): ErrorDto => {
  const originalError: any = error.extensions.originalError;
  const newError = new ErrorDto(originalError.statusCode);

  return newError;
};



/* src/HttpExceptionFilter.ts */
/* 아래 클래스 추가 */

export class CustomError extends BadRequestException {
  errorCode: number;
  
  constructor(errorCode: number) {
    super({ ok: false, statusCode: errorCode });
    this.errorCode = errorCode;
  }
}

 

/* src/common/types/exception.types.ts */

export enum ErrorCode {
  UNAUTHORIZED = 10000,
  FORBIDDEN = 10001,
  EXPIRED_TOKEN = 10002,
  QUEUE_EMPTY = 30000,
  QUEUE_ALREADY_ON_RUNNING = 30001,
  INTERNAL_SERVER_ERROR = 50000,
  AUTH_PASSWORD_SHORT = 20000,
  AUTH_INVALID_PASSWORD = 20001,
  AUTHORIZATION_NOT_EXIST = 20002,
  GPM_CATALOG_REJECT_LIST_EMPTY = 21000,
  GPM_CATALOG_REJECT_LIST_BE_ONE_OR_MORE = 21001,
}
export const ErrorMessageV1 = {
  [ErrorCode.UNAUTHORIZED]: {
    code: 10000,
    message: '로그인정보가 잘못되었습니다.',
  },
  [ErrorCode.FORBIDDEN]: { code: 10001, message: 'Access forbidden.' },
  [ErrorCode.EXPIRED_TOKEN]: { code: 10002, message: 'Token has expired.' },
  [ErrorCode.QUEUE_EMPTY]: { code: 30000, message: 'Queue is empty.' },
  [ErrorCode.QUEUE_ALREADY_ON_RUNNING]: {
    code: 30001,
    message: 'Queue is already on running.',
  },
  [ErrorCode.INTERNAL_SERVER_ERROR]: {
    code: 50000,
    message: 'Internal server error.',
  },
  [ErrorCode.AUTH_PASSWORD_SHORT]: {
    code: 20000,
    message: 'Password is too short.',
  },
  [ErrorCode.AUTH_INVALID_PASSWORD]: {
    code: 20001,
    message: 'Invalid password.',
  },
  [ErrorCode.AUTHORIZATION_NOT_EXIST]: {
    code: 20002,
    message: 'Authorization does not exist.',
  },
  [ErrorCode.GPM_CATALOG_REJECT_LIST_EMPTY]: {
    code: 21000,
    message: 'Catalog reject list is empty.',
  },
  [ErrorCode.GPM_CATALOG_REJECT_LIST_BE_ONE_OR_MORE]: {
    code: 21001,
    message: 'Catalog reject list should be one or more.',
  },
};

 

 

/* src/common/dtos/exception.dto.ts */

import { ErrorCode, ErrorMessageV1 } from '../types/exception.types';

export class ErrorDto {
  message: string;

  constructor(errorCode: ErrorCode) {
    this.message = `[${errorCode}] - ${
      ErrorMessageV1[ErrorCode[ErrorCode[errorCode]]].message
    }`;
  }
}

 

 

위와같이 코드 작업 후 실제 Exception을 발생시킬때,

throw new CustomError(ErrorCode.UNAUTHORIZED);

 

위와 같이 발생시키면 되며,

클라이언트에서는 Response 된 에러에서 Message에서 코드와 메시지를 사용하여 에러메시지를 공통적으로 처리할 수 있다.


반응형

+ Recent posts