Nodejs

 NestJS에서 gRPC 기반 User Microservice 구축하기

NestJS로 마이크로서비스를 개발할 때, gRPC를 활용하면 타입 안정성과 성능을 동시에 확보할 수 있습니다. 이번 글에서는 기존 AMQP(RabbitMQ) 기반 구조를 gRPC로 전환하고, UserMicroservice를 구축하는 과정을 정리합니다.

 

 

1.환경 설정 및 패키지 설치

먼저 필요한 패키지를 설치합니다:

pnpm add -D @grpc/grpc-js @grpc/proto-loader ts-proto

그리고 .proto 파일을 TypeScript로 변환하기 위한 명령어를 package.json에 등록합니다:

"scripts": {
  "proto:gen": "npx protoc --ts_proto_out=./libs/common/src/grpc --ts_proto_opt=nestJs=true,addGrpcMetadata=true -I ./proto ./proto/*.proto"
}

변환 실행:

pnpm run proto:gen

변환된 파일은 libs/common/src/grpc 폴더에 생성됩니다.

 

 

2. gRPC 서버 설정

main.ts에서 gRPC 서버를 설정합니다:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { UserMicroservice } from '@app/common';
import { join } from 'path';
import { ConfigService } from '@nestjs/config';

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

  app.connectMicroservice<MicroserviceOptions>({
    transport: Transport.GRPC,
    options: {
      package: UserMicroservice.protobufPackage,
      protoPath: join(process.cwd(), 'proto/user.proto'),
      url: configService.getOrThrow('GRPC_URL'),
    },
  });

  await app.startAllMicroservices();
}
bootstrap();

.env 파일에 gRPC URL을 정의합니다:

GRPC_URL=user:3001

???? Microservice 모듈 정리

libs/common/src/grpc 폴더에 각 서비스별로 파일을 생성하고, index.ts에서 다음과 같이 정리합니다:

export * as UserMicroservice from './user';
export * as OrderMicroservice from './order';
export * as PaymentMicroservice from './payment';
export * as ProductMicroservice from './product';
export * as NotificationMicroservice from './notification';

 

 

컨트롤러 구현 예시

AuthController

@Controller('auth')
export class AuthController implements UserMicroservice.AuthServiceController {
  constructor(private readonly authService: AuthService) {}

  parseBearerToken(payload: UserMicroservice.ParseBearerTokenRequest) {
    return this.authService.parseBearerToken(payload.token, false);
  }

  registerUser(registerDto: UserMicroservice.RegisterUserRequest) {
    const { token } = registerDto;
    if (token === null) {
      throw new UnauthorizedException('토큰을 입력해주세요!');
    }
    return this.authService.register(token, registerDto);
  }

  loginUser(loginDto: UserMicroservice.LoginUserRequest) {
    const { token } = loginDto;
    if (token === null) {
      throw new UnauthorizedException('토큰을 입력해주세요!');
    }
    return this.authService.login(token);
  }
}

 

 

UserController

@Controller()
export class UserController implements UserMicroservice.UserServiceController {
  constructor(private readonly userService: UserService) {}

  getUserInfo(data: UserMicroservice.GetUserInfoRequest) {
    return this.userService.getUserById(data.userId);
  }
}

 

 

 

 

 

about author

PHRASE

Level 60  라이트

마음이란 삶의 근원과 기쁨을 동시에 담고 있는 곳이지만 그 실체는 고통에 물들어 있지 않은 청정무구한 진여(眞如) 바로 그것이다. -원효

댓글 ( 0)

댓글 남기기

작성