LoginSignup
9
2

More than 3 years have passed since last update.

【GoとgRPCとバリデーション】go-proto-validatorsでgrpcurlを使えるようにする

Last updated at Posted at 2019-12-23

はじめに

gRPCサーバのバリデーションを実装するにあたって、go-proto-validatorsは大変便利なのですが、gRPCクライアントツールで動作確認できないという罠に嵌ったので、原因と解決策を共有します。

go-proto-validatorsの基本

go-proto-validatorsとは?

go-proto-validatorsはGo向けのgRPCのバリデーションツールです。
protoファイルに直接バリデーションルールを記載することでIF情報を一元管理できるようになるのと、バリデーションコードの自動生成ができるのが良いところです。

使い方やルール一覧などの詳細はGitHubのページを確認してください。
Star数の割にはかなり良さそうです。

なぜgo-proto-validatorsを使いたいのか?

gRPCサーバのバリデーション実装には、REST-APIサーバ同様にozzo-validatorを使っていたのですが、下記の課題がありました。

  • バリデーションを自分で実装するのが面倒くさい
  • IF仕様書にバリデーション情報をかけない(コメントで書くことはできるけどダサい)
  • コメントだとダサいから別ファイル(Markdown)でバリデーション仕様管理してたけどとてもイケてなかった

ちなみに、ozzo-validationは良いライブラリですし、別システムでも使っていますし、紹介記事も書いていますので、非難するつもりはありません。

また、「わざわざgRPCじゃなくてこれまで通りRESTで充分なんじゃないの?」という声に対しても、バリデーション実装の自動生成を一つの理由にあげることができます。(小さい理由ですが)
なぜかというと、私の所属するチームでは、REST-APIサーバを実装する際にはopenapi-generatorを利用しているのですが、スキーマが自動生成時に上書きされてしまうので、バリデーション実装を自動生成してくれるgo-playground/validatorを使っておらず、ozzo-validationを使って自前で実装しているからです。(それでもOpenAPIのコード自動生成の恩恵の方が大きいという判断)

問題発生!gRPCクライアントツールでリクエストできない

grpc_cli, evans, grpcurlなどのgRPCクライアントツールは、go-proto-validatorsを利用したサーバに正常にリクエストができません。下は実際に実行した例です。

grpc_cliの失敗例
$ grpc_cli call localhost:50051 YourService 'key1: "value1"' --metadata="authorization:api_key"
[libprotobuf ERROR google/protobuf/descriptor.cc:3587] Invalid proto descriptor for file "products.proto":
[libprotobuf ERROR google/protobuf/descriptor.cc:3590]   github.com/mwitkow/go-proto-validators/validator.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors.
Method name not found
Failed to find method YourService in proto files.
Method name not found
Method name not found
Failed to parse request.
grpcurlの失敗例
$ grpcurl -plaintext -d '{"key1": "value1"}' -H "authorization:api_key" localhost:50051 YourService
Error invoking method "YourService": target server does not expose service "YourService"

原因はgo-proto-validatorsが依存しているgogo/protobufServer Reflectionに対応していないことです。
https://github.com/mwitkow/go-proto-validators/issues/34#issuecomment-403082678

Server Reflectionは、gRPCサーバの情報提供や通信接続をダイレクトに利用できるようにしてくれる機能です。gRPCクライアントツールは基本的にこのServer Reflectionを使っています。

本件についてはissueが現在(2019/11)もgrpc上で上がっています。
https://github.com/grpc/grpc-go/issues/1873

解決方法

grpcurlであれば以下の2Stepsで実行が成功するようになりました!

Step1. import-pathとprotoオプションを指定する

コマンド例
$ grpcurl -insecure -import-path your_service_directory -proto your_service.proto -d '{"key1": "value1"}' -H "authorization:api_key" localhost:50051 YourService

-import-path value
The path to a directory from which proto sources can be imported, for use with -proto flags.

-proto value
The name of a proto source file. Source files given will be used to determine the RPC schema instead of querying for it from the remote server via the gRPC reflection API.

とあるように、import-pathオプションはprotoオプションとセットで使うようです。
protoオプションを指定することでServer Reflectionを使用しないようにできます。
your_service_directoryには、protoファイルが配置されているディレクトリパスを指定してます。

Step2. validator.protoファイルをローカルに配置する

go-proto-validatorsvalidator.protoファイルをローカルに配置します。
validator.protoはgo getで取得したものをコピペしてもいいですし、githubからダウンロードして取得しても良いです。
リモートだとうまくいかなケースがあったため、このような対応をしています。

配置場所は上記のimport-pathオプションで指定したディレクトリ配下でgithub.com/mwitkow/go-proto-validators/validator.protoという具合にします。

これで、grpcurlでリクエストできるようになりました。
やったね!

注意点

この解決策には問題があります。
それは、大元のgo-proto-validators/validator.protoの変更に追従できないことです。
ただ、このファイルの変更はあまりなさそうなのと、git submodleでの対応も可能だと思われます。

最後に

gRPCは最初は予想外のところでつまずくことが多いですが、やってみると楽しいです。

結局、Team Leaderのおかげで自己解決できましたが、Gophersスラックにデビューできたので、詰まって良かったです。
https://gophers.slack.com/archives/C03RB2KAD/p1573531143286700

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2