반응형
에러 핸들링(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에서 코드와 메시지를 사용하여 에러메시지를 공통적으로 처리할 수 있다.
반응형
'BackEnd > Nest' 카테고리의 다른 글
[NestJS] TypeORM > CustomRespository 사용방법 (2) | 2024.01.21 |
---|---|
[NestJS] NestJS에 Guard를 사용해 Role을 적용해보기 - 기록용 (0) | 2024.01.21 |
[Nest.js] Jest > e2e테스트 detectOpenHandles (0) | 2024.01.20 |
TypeORM 설치 (0) | 2024.01.13 |
Config Module(.env) 사용하기 (0) | 2024.01.13 |