経緯
goで作っているサービスのgRPC通信の動作確認用にgrpcurl
というクライアントツールを使ってみました。
別クライアントのgrpc_cli
はMacローカルにbrewでインストールしてもうまくパスが通らず諦めました。
環境
$ sw_vers
ProductName: macOS
ProductVersion: 11.5.1
BuildVersion: 20G80
$ go version
go version go1.16.6 darwin/arm64
$grpcurl --version
grpcurl 1.8.2
インストールはおもむろに brew install grpcurl
で行いました。
#手順
1. サーバーを立ち上げる
$ cd $GOPATH/src/github.com/hoge-monorepo
$ go run cmd/xxxx/main.go
{"level":"INFO","ts":"2021-08-16T16:33:21.649229+09:00","caller":"auth/main.go:81","function":"main.runGRPCServer","message":"Start GRPC server at [::]:50051, TLS = false","hostname":"XXXs-M1-MacBook-Pro.local"}
*xxxxはサービス名
2. 利用可能なサービス一覧を確認する
$ grpcurl localhost:50051
Failed to dial target host "localhost:50051": tls: first record does not look like a TLS handshake
あれ?
$ grpcurl --help
...
-plaintext
Use plain-text HTTP/2 when connecting to server (no TLS).
...
TLS無しのアクセス時には-plaintext
は必須。ということで
$ grpcurl -plaintext localhost:50051 list
grpc.reflection.v1alpha.ServerReflection
proto.AuthManagement
$ grpcurl -plaintext localhost:50051 describe
grpc.reflection.v1alpha.ServerReflection is a service:
service ServerReflection {
rpc ServerReflectionInfo ( stream .grpc.reflection.v1alpha.ServerReflectionRequest ) returns ( stream .grpc.reflection.v1alpha.ServerReflectionResponse );
}
proto.AuthManagement is a service:
service AuthManagement {
rpc Login ( .proto.LoginRequest ) returns ( .proto.LoginResponse ) {
option (.google.api.http) = { post:"/auth/v1/login" body:"*" };
}
rpc VerifyToken ( .proto.VerifyTokenRequest ) returns ( .proto.VerifyTokenResponse ) {
option (.google.api.http) = { put:"/auth/v1/verify-token" body:"*" };
}
}
これで、このAPIが露出している全てのサービスall exposed services
を出力できました。
(gRPCのmethodは全てPOSTなので、通常のcURLのように-X POST
のような指定は不要です。)
3-1. 実際にAPIコールしてみる
$ grpcurl -plaintext localhost:50051 list proto.AuthManagement
proto.AuthManagement.Login
proto.AuthManagement.VerifyToken
$ grpcurl -plaintext -d '{"email": "hoge@example.com", "password": "1234"}' localhost:50051 proto.AuthManagement/Login
{
"data": {
"access_token": "eyJhbGciOi......",
"refresh_token": "eyJhbGciOi......"
}
}
3-2. リクエストパラメータを標準入力で入れたい場合
$ grpcurl -plaintext -d @ localhost:50051 proto.AuthManagement/Login
(ここで標準入力の待ち受けモードとなるので、おもむろにJSONをペースト。)
{
"email": "hoge@example.com",
"password": "1234"
}
(ここで「control + D」を押して終了。)
{D
"data": {
"access_token": "eyJhbGciOi......",
"refresh_token": "eyJhbGciOi......"
}
}
3-3. より詳細な情報を標準出力に表示したい場合
-v
か-vv
で出力が冗長(verbose)になります。
$ grpcurl -v -plaintext -d '{"email": "hoge@example.com", "password": "1234"}' localhost:50051 proto.AuthManagement/Login
Resolved method descriptor:
rpc Login ( .proto.LoginRequest ) returns ( .proto.LoginResponse ) {
option (.google.api.http) = { post:"/auth/v1/login" body:"*" };
}
Request metadata to send:
(empty)
Response headers received:
content-type: application/grpc
Response contents:
{
"data": {
"access_token": "eyJhbGciOi......",
"refresh_token": "eyJhbGciOi......"
}
}
Response trailers received:
(empty)
Sent 1 request and received 1 response
以上、簡単に説明してきました。
他にも特殊なAPIコールの仕方が出てきたら追記したいと思います。
以下、2021.10.28追記
4. import pathを指定する場合
protoファイルを指定してgRPCコールを試す際に、protoファイル中のimport文がうまく動かないことがあります。
例えば以下のようなファイルがあったとします。
$ tree -L 3 ./proto
proto
├── google
│ └── api
│ ├── annotations.proto
│ ├── http.proto
│ └── httpbody.proto
└── account
├── auth_management_service.proto
└── auth_message.proto
3 directories, 5 files
syntax = "proto3"
package proro;
import "google/api/annotations.proto"; <------ import先参照不可エラー
import "auth_message.proro"; <------ import先参照不可エラー
option go_package = ".;account";
service AuthManagement {
rpc Login(LoginRequest) returns (LoginResponse) {
option (google.api.http) = {
post : "/v1/login"
body : "*"
}
}
}
この状態で徐にgrpcurl
コマンドを叩くと、
grpcurl -plaintext \
-d '{"email": "hoge@example.com", "password": "1234"}' \
-proto account/auth_management_service.proto \
127.0.0.1:8011 \
proto.AuthManagement/Login
Failed to process proto source files.: could not parse given files: open account/auth_management_service.proto: no such file or directory
と怒られてしまいます。
ここでgrpcurl
コマンドに-import-path ./proto
オプションをつけると、
grpcurl -plaintext \
-d '{"email": "hoge@example.com", "password": "1234"}' \
-import-path ./proto \
-proto account/auth_management_service.proto \
127.0.0.1:8011 \
proto.AuthManagement/Login
Failed to process proto source files.: could not parse given files: account/auth_management_service.proto:6:8: open proto/auth_management.proto: no such file or directory
となります。そのため、account/フォルダの場所を明示的に示してあげる必要があります。
-import-path ./proto/account
を追加します。
grpcurl -plaintext \
-d '{"email": "hoge@example.com", "password": "1234"}' \
-import-path ./proto \
-import-path ./proto/account \
-proto account/auth_management_service.proto \
127.0.0.1:8011 \
proto.AuthManagement/Login
Failed to process proto source files.: could not parse given files: account/auth_message.proto:6:8: open proto/validate/validate.proto: no such file or directory
このvalidate/validate.proto
というのはバリデーションのためのprotocプラグインで、このプロジェクト配下に存在するものではなく、ご自身のGOPATH配下のパスを指定する必要があります。
$ go get -d github.com/envoyproxy/protoc-gen-validate
これでご自身のGOPATH配下にprotoc-gen-validate
が無事インストールされます。
-import-path ${GOPATH}/src/github.com/envoyproxy/protoc-gen-validate
を追加します。
grpcurl -plaintext \
-d '{"email": "hoge@example.com", "password": "1234"}' \
-import-path ./proto \
-import-path ./proto/account \
-import-path ${GOPATH}/src/github.com/envoyproxy/protoc-gen-validate \
-proto account/auth_management_service.proto \
127.0.0.1:8011 \
proto.AuthManagement/Login
{
"data": {
"access_token": "eyJhbGciOi......",
"refresh_token": "eyJhbGciOi......"
}
}
これで無事、import文の参照切れがなくなりAPIコールが正しく通るようになりました。