NestJS - gRPC proto

오픈소스·2024년 3월 7일
0
post-thumbnail

샘플 코드가 있다.

// hero/hero.proto
syntax = "proto3";

package hero;

service HeroesService {
  rpc FindOne (HeroById) returns (Hero) {}
}

message HeroById {
  int32 id = 1;
}

message Hero {
  int32 id = 1;
  string name = 2;
}

hero.proto 화일을 https://www.npmjs.com/package/ts-proto 이용해 컴파일하면
(protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=. ./hero.proto),
interface, decorator 등을 포함한 hero.ts 화일이 생긴다.

/* eslint-disable */
import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices";
import { Observable } from "rxjs";

export const protobufPackage = "hero";

export interface HeroById {
  id: number;
}

export interface Hero {
  id: number;
  name: string;
}

export const HERO_PACKAGE_NAME = "hero";

export interface HeroesServiceClient {
  findOne(request: HeroById): Observable<Hero>;

  findMany(request: Observable<HeroById>): Observable<Hero>;
}

export interface HeroesServiceController {
  findOne(request: HeroById): Promise<Hero> | Observable<Hero> | Hero;

  findMany(request: Observable<HeroById>): Observable<Hero>;
}

export function HeroesServiceControllerMethods() {
  return function (constructor: Function) {
    const grpcMethods: string[] = ["findOne"];
    for (const method of grpcMethods) {
      const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method);
      GrpcMethod("HeroesService", method)(constructor.prototype[method], method, descriptor);
    }
    const grpcStreamMethods: string[] = ["findMany"];
    for (const method of grpcStreamMethods) {
      const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method);
      GrpcStreamMethod("HeroesService", method)(constructor.prototype[method], method, descriptor);
    }
  };
}

export const HEROES_SERVICE_NAME = "HeroesService";

여기까지는 client, server 공통사항이고,


https://levelup.gitconnected.com/step-by-step-guide-grpc-microservices-in-nestjs-554b498d3f7

server

https://github.com/nestjs/nest/blob/master/sample/04-grpc/src/hero/hero.controller.ts 만큼 복작하지 않게,
hero.ts 를 이용해 아래와 같이 간단하게 작성할 수 있다.

import { Controller, UseInterceptors } from '@nestjs/common';
import { GrpcLoggingInterceptor } from '@packages/lib';
import { Observable } from 'rxjs';

import { Hero, HeroById, HeroesServiceController, HEROES_SERVICE_NAME } from './hero';

@UseInterceptors(GrpcLoggingInterceptor)
@Controller()
export class HeroController implements HeroesServiceController {
    @GrpcMethod(HEROES_SERVICE_NAME, 'findOne')
    findOne(request: HeroById): Promise<Hero> | Observable<Hero> | Hero {
        const items = [
            { id: 1, name: 'John' },
            { id: 2, name: 'Doe' }
        ];
        return items.find(({ id }) => id === request.id);
    }
}

client

https://docs.nestjs.com/microservices/grpc#client 비슷하지만,
hero.ts 를 이용해 아래와 같이 작성할 수 있다.

import { ClientGrpc } from '@nestjs/microservices';
import { Inject, Injectable } from '@nestjs/common';

import { HEROES_SERVICE_NAME, HeroesServiceClient } from './hero';

@Injectable()
export class CommonGrpcService {
    private heroesService: HeroesServiceClient;

    constructor(@Inject('HERO_PACKAGE') private client: ClientGrpc) {}

    onModuleInit() {
        this.heroesService = this.client.getService<HeroesServiceClient>(HEROES_SERVICE_NAME);
    }

    getHero() {
        return this.heroesService.findOne({ id: 1 });
    }
}

결론

client, server 둘 다 gRPC code generation(dynamic, static)과 관계 없이
https://github.com/nestjs/nest/tree/master/sample/04-grpc/src/hero/interfaces
https://github.com/nestjs/nest/blob/master/sample/04-grpc/src/hero/hero.controller.ts#L12-L15

export interface HeroById {
  id: number;
}

export interface Hero {
  id: number;
  name: string;
}

interface HeroesService {
  findOne(data: HeroById): Observable<Hero>;
  findMany(upstream: Observable<HeroById>): Observable<Hero>;
}

타입을 선언해야 한다.

그런데, https://www.npmjs.com/package/ts-proto 이용해 컴파일하면,
server 도 간단하게 구현할 수 있고, client, server에 필요한 type 도 생성된다.

참고)

0개의 댓글