【入門】コピペでできる、Node.js(NestJS) + gRPCでサーバー構築
はじめに
個人的にはgRPCの学習コストは結構高く、技術記事を見ても途中で上手くいかず過去困ることがありました。
なので、gRPCサーバー立てて、ターミナルのクライアントからのアクセスをコピペでサクッとできる!をゴールに記事を書きますので、最初の足掛かりとしていただけたらと思います。
なお、NestJSを使ったのはただの好みです。
環境
タイトル | バージョン |
---|---|
Node.js | v18.14.2 |
npm | 9.5.0 |
全体の流れ
- 初期構築
- 設定ファイル書き換え
- protoファイル作成
- protoファイルからtsファイル生成
- gRPCサーバーの実装
- クライアントツールのEvansからgRPCサーバーにアクセス
初期構築
まずはじめに、アプリケーション開発を支援してくれるNest CLIをインストールし、NestJSプロジェクトを作成します。
npm or yarn or pnpm のどれにするか聞かれますが、今回はnpmを選択します。
$ npm i -g @nestjs/cli
$ nest new project-name
$ cd project-name
protoファイルからTypeScriptの型定義を生成してくれて、かつNestJSをガッチリサポートしているts-protoを入れます。
また、gRPCサーバー構築に必要なパッケージをインストールします。
$ npm install ts-proto
$ npm install @grpc/grpc-js @grpc/proto-loader @nestjs/microservices
Nest CLIでひな形のファイルを生成しておきましょう。
$ nest g controller hero
$ nest g module hero
$ nest g service hero
ひとまずサーバー起動することを確認します。
$ npm start
ブラウザにhttp://localhost:3000
と入力して、Hello World!
となれば確認OKです。
nest-cli.jsonの書き換え
Nestの設定ファイルを書き換えます。
compilerOptions
にassets
とwatchAssets
を指定します。
コンパイルすると通常tsファイル以外はdist
に配置してくれませんが、assets
に書くと指定したファイルを持っていってくれるようになります。
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": ["**/*.proto"],
"watchAssets": true
}
}
protoファイル作成
src/heroディレクトリにprotoファイルを新規作成します。
// 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;
}
protoファイルからtsファイルを生成
下記コマンドを実行してみましょう。hero.ts
が生成されます。
protoc --ts_proto_opt=nestJs=true --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=. ./src/hero/hero.proto
main.tsの編集
src/main.tsを編集します。
ポートの指定ないけどいいの?と思うかもしれませんが、この構築方法だとデフォルトが5000番ポートに変更されます。
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { join } from 'path';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.GRPC,
options: {
package: 'hero',
protoPath: join(__dirname, 'hero/hero.proto'),
},
},
);
await app.listen();
}
bootstrap();
hero.controller.tsの編集
src/hero/hero.controller.tsを編集します。
@GrpcMethod
にprotoファイルで指定したサービス名を定義しています。
import { Controller } from '@nestjs/common';
import { GrpcMethod } from '@nestjs/microservices';
import { HeroById, Hero } from './hero';
@Controller()
export class HeroesController {
@GrpcMethod('HeroesService', 'FindOne')
findOne(data: HeroById): Hero {
const items = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Doe' },
];
return items.find(({ id }) => id === data.id);
}
}
hero.module.tsの編集
src/hero/hero.module.tsを編集します。
import { Module } from '@nestjs/common';
import { HeroesController } from './hero.controller';
import { HeroService } from './hero.service';
@Module({
providers: [HeroService],
controllers: [HeroesController],
})
export class HeroModule {}
hero.service.tsの編集
src/hero/hero.service.tsを編集します。(多分編集不要)
import { Injectable } from '@nestjs/common';
@Injectable()
export class HeroService {}
app.module.tsの編集
src/app.module.tsを編集します。
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { HeroesController } from './hero/hero.controller';
import { HeroModule } from './hero/hero.module';
@Module({
imports: [HeroModule],
controllers: [AppController, HeroesController],
providers: [AppService],
})
export class AppModule {}
サーバー起動🚀
npm start
でサーバー起動します。
Evansで確認
EvansというgRPCのクライアントツールがあるのでそこから確認してみましょう。
別のターミナルを開き、まずはEvansをインストールします。
brew tap ktr0731/evans
brew install evans
ターミナルから今回のプロジェクトルートまで移動してコマンドを実行します。
evans --host localhost -p 5000 src/hero/hero.proto
下記の画面になれば成功です。
show service
コマンドで情報が確認できます。
ターミナルにcall FindOne
と打って、その後1
を入力します。
わーい!返ってきたぞーい!!
ちなみにEvansはCmd + Dで終了になります。
さいごに
リポジトリは下記にあります。
参考
Discussion