Chapter 04無料公開

grpcurlコマンドからランブックを生成する

Ken’ichiro Oyama
Ken’ichiro Oyama
2023.01.06に更新

ターミナルからgPRCリクエストを送信するために使われるコマンドとしてgRPCurl ( grpcurl )があります。

https://github.com/fullstorydev/grpcurl

runnはcurlコマンドと同様にgrpcurlコマンドからもランブックを生成できます。

まずgrpcurlコマンドを組み立てます。

例として grpcb.in:9001hello.HelloService/SayHello メソッドへリクエストを送信します。

$ grpcurl -d '{"greeting": "alice"}' grpcb.in:9001 hello.HelloService/SayHello
{
  "reply": "hello alice"
}

レスポンスが返ってきていることがわかります。

runn new でgrpcurlコマンドをランブック形式に変換する

grpcurlコマンドの先頭に runn new -- をつけて実行すると、grpcurlコマンドをランブック形式に変換して標準出力に出力します。

$ runn new -- grpcurl -d '{"greeting": "alice"}' grpcb.in:9001 hello.HelloService/SayHello
desc: Generated by `runn new`
runners:
  greq: grpc://grpcb.in:9001
steps:
- greq:
    hello.HelloService/SayHello:
      message:
        greeting: alice

--and-run オプションで、grpcurlコマンドを変換したランブックを実行して test: も生成する

--and-run オプションは、対象(今回はgrpcurlコマンド)ランブック形式に変換するだけでなく、実際にそのランブックを実行して受け取ったレスポンスを test: セクションとして追加するオプションです。

grpcurlコマンドの先頭に runn new --and-run -- をつけて実行すると、grpcurlコマンドを test: セクション付きのランブック形式に変換して標準出力に出力します。

$ runn new --and-run -- grpcurl -d '{"greeting": "alice"}' grpcb.in:9001 hello.HelloService/SayHello
desc: Generated by `runn new`
runners:
  greq: grpc://grpcb.in:9001
steps:
- greq:
    hello.HelloService/SayHello:
      message:
        greeting: alice
  test: |
    current.res.headers['content-type'][0] == "application/grpc"
    && current.res.headers['trailer'][0] == "Grpc-Status"
    && current.res.headers['trailer'][1] == "Grpc-Message"
    && current.res.headers['trailer'][2] == "Grpc-Status-Details-Bin"
    && compare(current.res.message, {"reply":"hello alice"})
    && current.res.status == 0

[コラム] grpcurlコマンドのパース

runnではgrpcurlコマンドのパースに github.com/k1LoW/grpcurlreq パッケージを使用しています。

https://github.com/k1LoW/grpcurlreq

github.com/k1LoW/curlreq のgRPCurl版の位置づけです。

ただ、gRPCにはHTTPと違って *http.Request のような標準パッケージで用意されている共通のリクエストの型はありませんので、コマンドのパースまでにとどめています。

package main

import (
	"encoding/json"
	"fmt"
	"log"

	"github.com/k1LoW/grpcurlreq"
)

func main() {
	cmd := `grpcurl -d '{"id": 1234, "tags": ["foo","bar"]}' grpc.server.com:443 my.custom.server.Service/Method`
	p, err := grpcurlreq.Parse(cmd)
	if err != nil {
		log.Fatal(err)
	}
	b, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(b))

	// Output:
	// {"addr":"grpc.server.com:443","method":"my.custom.server.Service/Method","messages":[{"id":1234,"tags":["foo","bar"]}]}
}