技術っぽいことを書いてみるブログ

PythonとかVue.jsとか技術的なことについて書いていきます。

NestJsでgRPCやってみた(Server編)

やること

  • NestJsでgPRCのサービスを定義する

事前準備

gPRCを使うための関連ライブラリをインストールする。

npm i @nestjs/microservices
npm i @grpc/grpc-js @grpc/proto-loader

.protoの定義

gRPCのAPI定義を定義するprotoファイルを定義します。

proto/postCode.proto

syntax = "proto3";

package postCode;

service PostCodeService {
  rpc FindOne (PostCode) returns (Address) {}
}

message PostCode {
  int32 id = 1;
}

message Address {
  int32 id = 1;
  string prefectures = 2;
  string address1 = 3;
  string address2 = 4;
} 
  • syntax : バージョンの指定
  • package:パッケージを指定する
  • service:サービスを定義する
    • rpc:サービス内のメソッドになる部分を定義する
      • 上記の例だと、PostCodeServiceにFineOneメソッドがあり、引数はPostCodeという型(インターフェース)で受取り、Addressという型を返すよという内容
  • message:メッセージを定義する。型になる部分

main.tsの定義

nestjsのmain.tsでマイクロサービスを定義します。

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { join } from 'path';
import { GrpcOptions, Transport } from '@nestjs/microservices';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<GrpcOptions>(AppModule, {
    transport: Transport.GRPC,
    options: {
      url: 'localhost:5000',
      package: 'postCode',
      protoPath: join(__dirname, 'proto/postCode.proto'),
    },
  });
  await app.listen();
}
bootstrap();
  • NestFactory.createMicroserviceでNestJsがマイクロサービスとして起動することを定義する
  • transport: Transport.GRPC,にすることで、gRPCで通信しますよと定義する
  • optionsで、作成したprotoファイルへのパスとURLを設定する

controllerの定義

import { Controller, Get } from '@nestjs/common';
import { Address, PostCode } from './model';
import { GrpcMethod } from '@nestjs/microservices';

@Controller()
export class AppController {
  @GrpcMethod('PostCodeService')
  findOne(request: PostCode, metadata: any): Address {
    return {
      id: 6730000,
      prefectures: '兵庫県',
      address1: '三木市',
      address2: '××町',
    };
  }
}
  • コントローラーのメソッドに@GrpcMethodを付与する。
    • PostCodeServiceと定義することで、protoファイルのPostCodeService と紐付く
  • protoファイルのPostCodeService と紐付いたので、メソッド名はprotoファイルの定義と同様FindOneとなる
  • FineOneメソッドは、protoファイルを参照すると、PostCode型になり、Address型を返却するように定義されているので、メソッドの定義も同様にする
    • ただし、当然protoファイルのmessageはtypescriptのインターフェースとしてそのまま使えないので、interfaceを別途定義する必要あり
  • ※ここでは、適当に値を返すようにしています。

インターフェースの定義

リクエストとレスポンスのinterfaceをprotoファイルに合わせて定義する。

model.ts

export interface PostCode {
  id: number;
}

export interface Address {
  id: number;
  prefectures: string;
  address1: string;
  address2: string;
}

実行してみる

今回は呼び出し元のプロジェクトをまだ作成していないので、
ツールを使用して実行してみます。

仕様したツールは、こちらです。 github.com

まずは、npm run start:devでNestを起動

[10:31:09] Starting compilation in watch mode...

[10:31:10] Found 0 errors. Watching for file changes.

[Nest] 13252  - 2023/08/05 10:31:11     LOG [NestFactory] Starting Nest application...
[Nest] 13252  - 2023/08/05 10:31:11     LOG [InstanceLoader] AppModule dependencies initialized +7ms
[Nest] 13252  - 2023/08/05 10:31:11     LOG [NestMicroservice] Nest microservice successfully started +139ms

BloomRPCで実行。

という感じで、実行できました。

所感

意外と簡単にできました。

次回は、このgRPCを呼び出すnestjsを用意してみます。

こうした方がええでという意見がありましたら、コメントをお願いします。