NestJS gRPC ↔ HTTP 에러 매핑 및 예외 처리

ddoachi·2025년 6월 18일

TekaPicker

목록 보기
25/30

gRPC ↔ HTTP 에러 매핑표

gRPC CodegRPC StatusHTTP Status설명
0OK200 OK성공
1CANCELLED499 Client Closed Request클라이언트가 요청을 취소함
2UNKNOWN500 Internal Server Error알 수 없는 서버 오류
3INVALID_ARGUMENT400 Bad Request잘못된 파라미터
4DEADLINE_EXCEEDED504 Gateway Timeout시간 초과
5NOT_FOUND404 Not Found리소스를 찾을 수 없음
6ALREADY_EXISTS409 Conflict이미 존재함
7PERMISSION_DENIED403 Forbidden권한 없음
8RESOURCE_EXHAUSTED429 Too Many Requests요청 과다 또는 리소스 부족
9FAILED_PRECONDITION400 Bad Request요구 조건 미충족
10ABORTED409 Conflict트랜잭션 충돌 등
11OUT_OF_RANGE400 Bad Request범위 초과
12UNIMPLEMENTED501 Not Implemented아직 구현되지 않음
13INTERNAL500 Internal Server Error서버 내부 오류
14UNAVAILABLE503 Service Unavailable서비스 사용 불가
15DATA_LOSS500 Internal Server Error데이터 손실
16UNAUTHENTICATED401 Unauthorized인증되지 않음

예외 발생 코드 예시 (gRPC 서비스 내부)

import { RpcException } from '@nestjs/microservices';
import { status } from '@grpc/grpc-js';

throw new RpcException({
  code: status.NOT_FOUND,
  message: 'Category not found',
});

GrpcStatus가 아니라 status를 import해야 합니다:

import { status as GrpcStatus } from '@grpc/grpc-js';

NestJS Exception Filter로 gRPC → HTTP 매핑

// grpc-to-http.filter.ts

import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  NotFoundException,
  BadRequestException,
  ConflictException,
  InternalServerErrorException,
  UnauthorizedException,
  ForbiddenException,
  GatewayTimeoutException,
} from '@nestjs/common';
import { RpcException } from '@nestjs/microservices';
import { status as GrpcStatus, ServiceError } from '@grpc/grpc-js';

@Catch(RpcException)
export class GrpcToHttpFilter implements ExceptionFilter {
  catch(exception: RpcException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();

    const error = exception.getError() as ServiceError;

    let httpException;

    switch (error.code) {
      case GrpcStatus.NOT_FOUND:
        httpException = new NotFoundException(error.details);
        break;
      case GrpcStatus.ALREADY_EXISTS:
        httpException = new ConflictException(error.details);
        break;
      case GrpcStatus.INVALID_ARGUMENT:
        httpException = new BadRequestException(error.details);
        break;
      case GrpcStatus.UNAUTHENTICATED:
        httpException = new UnauthorizedException(error.details);
        break;
      case GrpcStatus.PERMISSION_DENIED:
        httpException = new ForbiddenException(error.details);
        break;
      case GrpcStatus.DEADLINE_EXCEEDED:
      case GrpcStatus.UNAVAILABLE:
        httpException = new GatewayTimeoutException(error.details);
        break;
      default:
        httpException = new InternalServerErrorException(error.details);
    }

    throw httpException;
  }
}

이 필터는 main.ts 또는 컨트롤러 레벨에서 등록해서 사용

profile
내일도 풀스택

0개의 댓글