Skip to content

Commit

Permalink
[connectrpc#477] add WithProtoJSONOptions() expose protojson marshall…
Browse files Browse the repository at this point in the history
…ing options
  • Loading branch information
greg-montoux committed Apr 14, 2023
1 parent c241c0e commit 3198410
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 8 deletions.
10 changes: 5 additions & 5 deletions codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ func (c *protoBinaryCodec) IsBinary() bool {
}

type protoJSONCodec struct {
name string
name string
marshalOptions protojson.MarshalOptions
unmarshalOptions protojson.UnmarshalOptions
}

var _ Codec = (*protoJSONCodec)(nil)
Expand All @@ -132,8 +134,7 @@ func (c *protoJSONCodec) Marshal(message any) ([]byte, error) {
if !ok {
return nil, errNotProto(message)
}
var options protojson.MarshalOptions
return options.Marshal(protoMessage)
return c.marshalOptions.Marshal(protoMessage)
}

func (c *protoJSONCodec) Unmarshal(binary []byte, message any) error {
Expand All @@ -144,8 +145,7 @@ func (c *protoJSONCodec) Unmarshal(binary []byte, message any) error {
if len(binary) == 0 {
return errors.New("zero-length payload is not a valid JSON object")
}
var options protojson.UnmarshalOptions
return options.Unmarshal(binary, protoMessage)
return c.unmarshalOptions.Unmarshal(binary, protoMessage)
}

func (c *protoJSONCodec) MarshalStable(message any) ([]byte, error) {
Expand Down
58 changes: 58 additions & 0 deletions codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import (

"github.com/bufbuild/connect-go/internal/assert"
pingv1 "github.com/bufbuild/connect-go/internal/gen/connect/ping/v1"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/apipb"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/structpb"
)
Expand Down Expand Up @@ -110,3 +112,59 @@ func TestJSONCodec(t *testing.T) {
assert.Sprintf(`error message should explain that "" is not a valid JSON object`),
)
}

func TestJSONCodecWithOptions(t *testing.T) {
t.Parallel()

codec := &protoJSONCodec{
name: "json",
marshalOptions: protojson.MarshalOptions{
Multiline: true,
Indent: " ",
UseProtoNames: true,
UseEnumNumbers: true,
EmitUnpopulated: true,
},
unmarshalOptions: protojson.UnmarshalOptions{
AllowPartial: false,
DiscardUnknown: true,
Resolver: nil,
},
}

in := apipb.Api{
Name: "api",
Version: "1.0",
}
data, err := codec.Marshal(&in)
if err != nil {
t.Error(err)
}

out := apipb.Api{}
err = codec.Unmarshal(data, &out)
if err != nil {
t.Error(err)
}

if out.Name != "api" || out.Version != "1.0" {
t.Error("values not preserved after round trip through marshal and unmarshal")
}

asJSON := string(data)
lines := strings.Count(asJSON, "\n")
spaces := strings.Count(asJSON, " ")

if lines == 0 || spaces == 0 {
t.Error("expected formatted JSON")
}

if !strings.Contains(asJSON, "\"source_context\"") {
t.Error("expected unpopulated fields to be included in message")
}

err = codec.Unmarshal([]byte(`{"name": "api", "foo": "bar"}`), &out)
if err != nil {
t.Error("expected unknown fields to be ignored, got error:", err)
}
}
21 changes: 18 additions & 3 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"context"
"io"
"net/http"

"google.golang.org/protobuf/encoding/protojson"
)

// A ClientOption configures a [Client].
Expand Down Expand Up @@ -77,7 +79,20 @@ func WithGRPCWeb() ClientOption {
// lowerCamelCase, zero values are omitted, missing required fields are errors,
// enums are emitted as strings, etc.
func WithProtoJSON() ClientOption {
return WithCodec(&protoJSONCodec{codecNameJSON})
return WithCodec(&protoJSONCodec{name: codecNameJSON})
}

// WithProtoJSONOptions is identical to WithProtoJSON, but also allows
// protojson marshalling options to be configured.
func WithProtoJSONOptions(
marshalOptions protojson.MarshalOptions,
unmarshalOptions protojson.UnmarshalOptions,
) ClientOption {
return WithCodec(&protoJSONCodec{
name: codecNameJSON,
marshalOptions: marshalOptions,
unmarshalOptions: unmarshalOptions,
})
}

// WithSendCompression configures the client to use the specified algorithm to
Expand Down Expand Up @@ -553,7 +568,7 @@ func withProtoBinaryCodec() Option {

func withProtoJSONCodecs() HandlerOption {
return WithHandlerOptions(
WithCodec(&protoJSONCodec{codecNameJSON}),
WithCodec(&protoJSONCodec{codecNameJSONCharsetUTF8}),
WithCodec(&protoJSONCodec{name: codecNameJSON}),
WithCodec(&protoJSONCodec{name: codecNameJSONCharsetUTF8}),
)
}

0 comments on commit 3198410

Please sign in to comment.