はじめに
例えばgRPCのメソッド、メッセージが以下だとして
syntax = "proto3";
import "google/protobuf/empty.proto";
import "google/api/annotations.proto";
package proto;
service TestService {
rpc Test (google.protobuf.Empty) returns (TestMessage) {
option (google.api.http) = {
get: "/test"
};
}
}
message TestMessage {
int32 a = 1;
bool b = 2;
string c = 3;
repeated string d = 4;
}
サーバからクライアントに送るメッセージが(極端ですが)以下のような内容だったとします。
TestMessage {
a: 0,
b: false,
c: "",
d: nil
}
grpc-gateway
経由で上記のメッセージを受け取った場合、空のJSONがレスポンスとして返ってきてしまいます。しかし、本当は以下のようなレスポンスが返ってきて欲しいです。
{ "a": 0, "b": false, "c": "", "d": [] }
ということでこのような設定にする方法を調べましたが、日本語の記事が見つからなかったのでQiitaに載せておきます。
やりかた
grpc-gateway
に、ゼロ値は省略せずにJSONの項目に含めてくれるオプションがありますので、それを指定してgrpc-gateway
のサーバを起動すれば万事解決です。
opts := []runtime.ServeMuxOption{
runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{OrigName: true, EmitDefaults: true}),
}
mux := runtime.NewServeMux(opts...)
原因
そもそも、なぜJSONのレスポンスに0や空文字が含まれていないのかという話ですが、Protocol Bufferから作成されたGo用の構造体にomitemptpy
が指定されているためです。
type TestMessage struct {
A int32 `protobuf:"varint,1,opt,name=a,proto3" json:"a,omitempty"`
B bool `protobuf:"varint,2,opt,name=b,proto3" json:"b,omitempty"`
C string `protobuf:"bytes,3,opt,name=c,proto3" json:"c,omitempty"`
D []string `protobuf:"bytes,4,rep,name=d,proto3" json:"d,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
しかも、このomitempty
はハードコードで指定されているのでprotoc
でコンパイルすときには必ず指定されてしまいます…
上記のような理由から、構造体に指定されているomitemptyを無視してゼロ値を出力するオプションがgrpc-gateway
側で作成されたようです。ありがとうphilipithomasさん!
参考リンク
golang protobuf remove omitempty tag from generated json tags -Stack Overflow
Support emitting default values in JSON #233