About
Nest.jsのgRPC Microserviceにおいて、複数のファイルやパッケージに分割されたprotoファイルを読み込む方法が公式チュートリアルでは分からなかったので、調べた結果を残しておきます。
前提
protoファイルとパッケージを次のような構成とします。
.
├── animal
│ ├── animal.proto
│ └── cat
│ └── cat.proto
└── human
└── human.proto
animal/animal.proto
package animal;
service AnimalService {
rpc GetAnimal (GetAnimalRequest) returns (GetAnimalResponse) {}
}
animal/cat/cat.proto
package animal.cat;
service CatService {
rpc GetCat (GetCatRequest) returns (GetCatResponse) {}
}
animal/human/human.proto
package human;
service HumanService {
rpc GetHuman (GetHumanRequest) returns (GetHumanResponse) {}
}
まとめると、パッケージも含めたサービスのリストは下記のようになります。
animal.AnimalService
animal.dog.DogService
human.HumanService
複数ファイル
まず、main.ts
で指定するGrpcOptions
は次のようになります。
src/main.ts
const app = await NestFactory.createMicroservice<GrpcOptions>(AppModule, {
transport: Transport.GRPC,
options: {
url: '0.0.0.0:6565',
// ポイント: パッケージを配列で指定
// ポイント: サブパッケージ(animal.dog)を含めると重複になるので含めない
package: ['animal', 'human'],
// ポイント: protoファイルを配列で指定
protoPath: [
join(__dirname, 'proto/animal/animal.proto'),
join(__dirname, 'proto/animal/dog/dog.proto'),
join(__dirname, 'proto/human/human.proto')
],
}
});
app.listenAsync();
次に、Controller
側ですが、最上位パッケージ直下のサービスなのか、サブパッケージのサービスなのかで、@GrpcMethod
デコレーターのサービス名の指定方法が変わってきます。
最上位パッケージ直下のサービス
@GrpcMethod('AnimalService', 'GetAnimal')
getAnimal(req: IGetAnimalRequest): Promise<IGetAnimalResponse> {
...
}
@GrpcMethod('HumanService', 'GetAnimal')
getAnimal(req: IGetHumanRequest): Promise<IGetHumanResponse> {
...
}
サブパッケージのサービス
// dog.が必要
@GrpcMethod('dog.DogService', 'GetDog')
getAnimal(req: IGetDogRequest): Promise<IGetDoglResponse> {
...
}
参考: 直面したエラー
ケース1: サブパッケージを重複読み込み
GrpcOptions
のパッケージしていにサブパッケージも含めてしまうと、次のようなエラーが発生してしまいました。
Method handler for /animal.dog.DogService/GetDog already provided
src/main.ts
const app = await NestFactory.createMicroservice<GrpcOptions>(AppModule, {
transport: Transport.GRPC,
options: {
url: '0.0.0.0:6565',
package: ['animal', 'animal.dog', 'human'],
protoPath: [
join(__dirname, 'proto/animal/animal.proto'),
join(__dirname, 'proto/animal/dog/dog.proto'),
join(__dirname, 'proto/human/human.proto')
],
}
});
app.listenAsync();
ケース2: サブパッケージのサービス名の名前解決が不正
サブパッケージのサービス名の名前解決
Method handler GetDog for /animal.dog.DogService/GetDog expected but not provided
@GrpcMethod('DogService', 'GetDog')
getAnimal(req: IGetDogRequest): Promise<IGetDoglResponse> {
...
}