Skip to content

Commit

Permalink
Support for proto3 optional fields, with EmitUnpopulated enabled on t…
Browse files Browse the repository at this point in the history
…he gRPC gateway (#7)

Support for proto3 optional fields, with
EmitUnpopulated enabled.

Issue: #5
  • Loading branch information
dpup authored Apr 22, 2024
1 parent 7acca20 commit 560fd31
Show file tree
Hide file tree
Showing 13 changed files with 531 additions and 101 deletions.
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ testdata:
@export PATH=$$PATH:$$(go env GOPATH)/bin; \
cd testdata && protoc -I . \
--grpc-gateway-ts_out=logtostderr=true:./ \
log.proto environment.proto ./datasource/datasource.proto
log.proto environment.proto ./datasource/datasource.proto

.PHONY: lint
lint:
Expand All @@ -23,6 +23,10 @@ go-tests:
go test ./...

.PHONY: integration-tests
integration-tests:
@export PATH=$$PATH:$$(go env GOPATH)/bin; \
integration-tests: integration-tests-gengo
cd integration_tests && ./scripts/test-ci.sh

.PHONY: integration-tests-gengo
integration-tests-gengo:
go install; \
cd integration_tests && ./scripts/gen-server-proto.sh
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

1. [Support for well-known wrapper types](https://github.com/grpc-ecosystem/protoc-gen-grpc-gateway-ts/pull/50)
2. Updated to support gRPC gateway v2 and latest protoc-gen-go
3. Support for proto3 optional fields (requires EmitUnpopulated enabled on the gRPC Gateway to function as expected)

## Getting Started:

Expand Down
2 changes: 0 additions & 2 deletions generator/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,6 @@ func fieldName(r *registry.Registry) func(name string) string {
if r.UseProtoNames {
return name
}

return strcase.ToLowerCamel(name)
}
}
Expand Down Expand Up @@ -546,7 +545,6 @@ func tsType(r *registry.Registry, fieldType data.Type) string {

return fmt.Sprintf("{[key: %s]: %s}", keyType, valueType)
}

typeStr := ""
if mapWellKnownType(info.Type) != "" {
typeStr = mapWellKnownType(info.Type)
Expand Down
18 changes: 16 additions & 2 deletions integration_tests/integration_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe("test grpc-gateway-ts communication", () => {

it("failing unary request", async () => {
try {
await CounterService.FailingIncrement({ counter: 199 }, { pathPrefix: "http://localhost:8081" });
await CounterService.FailingIncrement({ counter: 199 }, { pathPrefix: "http://localhost:8081" });
expect.fail("expected call to throw");
} catch (e) {
expect(e).to.have.property("message", "this increment does not work")
Expand Down Expand Up @@ -77,7 +77,7 @@ describe("test grpc-gateway-ts communication", () => {
const result = await CounterService.HTTPDelete({ a: 10 }, { pathPrefix: "http://localhost:8081" })
expect(result).to.be.empty
})

it('http get request with url search parameters', async () => {
const result = await CounterService.HTTPGetWithURLSearchParams({ a: 10, [getFieldName('post_req')]: { b: 0 }, c: [23, 25], [getFieldName('ext_msg')]: { d: 12 } }, { pathPrefix: "http://localhost:8081" })
expect(getField(result, 'url_search_params_result')).to.equal(70)
Expand All @@ -87,4 +87,18 @@ describe("test grpc-gateway-ts communication", () => {
const result = await CounterService.HTTPGetWithZeroValueURLSearchParams({ a: "A", b: "", [getFieldName('zero_value_msg')]: { c: 1, d: [1, 0, 2], e: false } }, { pathPrefix: "http://localhost:8081" })
expect(result).to.deep.equal({ a: "A", b: "hello", [getFieldName('zero_value_msg')]: { c: 2, d: [2, 1, 3], e: true } })
})

it('http get request with optional fields', async () => {
const result = await CounterService.HTTPGetWithOptionalFields({}, { pathPrefix: "http://localhost:8081" })
// opt fields should always be undefined.
expect(result).to.deep.equal({
[getFieldName('echo_str')]: "hello",
[getFieldName('echo_number')]: 123,
// echo_opt_ vars will be undefined.
[getFieldName('new_str')]: "",
[getFieldName('new_number')]: 0,
[getFieldName('new_opt_str')]: "",
[getFieldName('new_opt_number')]: 0
})
})
})
3 changes: 2 additions & 1 deletion integration_tests/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ func main() {
gateway := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{
Marshaler: &runtime.JSONPb{
MarshalOptions: protojson.MarshalOptions{
UseProtoNames: *origName,
UseProtoNames: *origName,
EmitUnpopulated: true, // Required to support optional fields as expected.
},
},
}))
Expand Down
2 changes: 1 addition & 1 deletion integration_tests/msg.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions integration_tests/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,18 @@ func (r *RealCounterService) HTTPGetWithZeroValueURLSearchParams(ctx context.Con
},
}, nil
}

func (r *RealCounterService) HTTPGetWithOptionalFields(ctx context.Context, in *OptionalFieldsRequest) (*OptionalFieldsResponse, error) {
var s string
var n int32
return &OptionalFieldsResponse{
EchoStr: in.Str + "hello",
EchoNumber: in.Number + 123,
EchoOptStr: in.OptStr,
EchoOptNumber: in.OptNumber,
NewStr: "",
NewNumber: 0,
NewOptStr: &s,
NewOptNumber: &n,
}, nil
}
Loading

0 comments on commit 560fd31

Please sign in to comment.