Reputation: 1851
I am new to grpc
and have been trying to just fetch a json
response from a webserver. The stub can then request the json
from the rpc
server.
In my .proto
file, I created a message type:
message Post {
int64 number = 1;
string now = 2;
string name = 3;
}
But I am not able to marshal the number
field, since protoc
produces the struct pb.go
file with a number
tag:
{
"no": "23",
"now": "12:06:46",
"name": "bob"
}
How can I force the Message
to be 'converted' with a tag other than the lowercase name of the message field? Such as using the json
tag no
, even if the field name in the Message
is number
.
Upvotes: 14
Views: 26860
Reputation: 29
Here is my solution, which is an friendly and compatible way for adding go struct tags in protobuf/grpc.
Fork protobuf-go repo to your own github account, and add a go tags feature into cmd/protoc-gen-go. Like this: https://github.com/hacksomecn/protobuf-go/commit/2443a0ee4696acaa9aa4bf8c2e0586d7c724c645
Install new-feature protoc-gen-go into you path. Like: go install github.com/hacksomecn/protobuf-go/cmd/protoc-gen-go@"v1.28.0-gotags"
Declare message field with an tailing comment, add go tags expr in comment. Go tags expr regexp format is (\s?)@go_tags\(` + "(`.*`)" + `\)\s
.
Like:
message HelloGoTags {
string Name = 1; // @go_tags(`json:"name,omitempty" yaml:"name" bson:"name" db:"name" gorm:"name" validate:"required"`) awesome name
}
protoc
compile .proto. Like:protoc --go_out=. --go_opt=paths=source_relative tags.proto
type HelloGoTags struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"name,omitempty" gorm:"name" validate:"required" yaml:"name" bson:"name" db:"name"` // awesome name
}
Upvotes: 0
Reputation: 169
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
// Result example:
// type Post struct {
// Number int64 `protobuf:"bytes,1,opt,name=number,json=no1,proto3" json:"no2"`
// }
message Post {
int64 number = 1 [json_name="no1", (gogoproto.jsontag) = "no2"];
}
,where:
jsonpb example:
import (
"bytes"
"testing"
"encoding/json"
"github.com/golang/protobuf/jsonpb"
"github.com/stretchr/testify/require"
)
func TestJSON(t *testing.T) {
msg := &Post{
Number: 1,
}
buf := bytes.NewBuffer(nil)
require.NoError(t, (&jsonpb.Marshaler{}).Marshal(buf, msg))
require.Equal(t, `{"no1":1}`, buf.String())
buf.Truncate(0)
require.NoError(t, json.NewEncoder(buf).Encode(msg))
require.Equal(t, `{"no2":1}`, buf.String())
}
More information about protobuf extensions
Upvotes: 13
Reputation: 5898
You can set a proto3 field option on the proto message definition with a json_name
message Post {
int64 number = 1 [json_name="no"];
string now = 2;
string name = 3;
}
Upvotes: 17