Skip to content

Commit

Permalink
gengateway: allow opting out patch feature
Browse files Browse the repository at this point in the history
Closes #839
  • Loading branch information
glerchundi authored and johanbrandhorst committed Jan 8, 2019
1 parent a6d3ad2 commit 96cb2e2
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 8 deletions.
5 changes: 4 additions & 1 deletion protoc-gen-grpc-gateway/gengateway/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ type generator struct {
useRequestContext bool
registerFuncSuffix string
pathType pathType
allowPatchFeature bool
}

// New returns a new generator which generates grpc gateway files.
func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, pathTypeString string) gen.Generator {
func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, pathTypeString string, allowPatchFeature bool) gen.Generator {
var imports []descriptor.GoPackage
for _, pkgpath := range []string{
"io",
Expand Down Expand Up @@ -82,6 +83,7 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix, p
useRequestContext: useRequestContext,
registerFuncSuffix: registerFuncSuffix,
pathType: pathType,
allowPatchFeature: allowPatchFeature,
}
}

Expand Down Expand Up @@ -142,6 +144,7 @@ func (g *generator) generate(file *descriptor.File) (string, error) {
Imports: imports,
UseRequestContext: g.useRequestContext,
RegisterFuncSuffix: g.registerFuncSuffix,
AllowPatchFeature: g.allowPatchFeature,
}
return applyTemplate(params, g.reg)
}
Expand Down
13 changes: 10 additions & 3 deletions protoc-gen-grpc-gateway/gengateway/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ type param struct {
Imports []descriptor.GoPackage
UseRequestContext bool
RegisterFuncSuffix string
AllowPatchFeature bool
}

type binding struct {
*descriptor.Binding
Registry *descriptor.Registry
Registry *descriptor.Registry
AllowPatchFeature bool
}

// GetBodyFieldPath returns the binding body's fieldpath.
Expand Down Expand Up @@ -153,7 +155,11 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) {
meth.Name = &methName
for _, b := range meth.Bindings {
methodWithBindingsSeen = true
if err := handlerTemplate.Execute(w, binding{Binding: b, Registry: reg}); err != nil {
if err := handlerTemplate.Execute(w, binding{
Binding: b,
Registry: reg,
AllowPatchFeature: p.AllowPatchFeature,
}); err != nil {
return "", err
}
}
Expand Down Expand Up @@ -268,6 +274,7 @@ func request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ctx cont
`))

_ = template.Must(handlerTemplate.New("client-rpc-request-func").Parse(`
{{$AllowPatchFeature := .AllowPatchFeature}}
{{if .HasQueryParam}}
var (
filter_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}} = {{.QueryParamFilter}}
Expand All @@ -284,7 +291,7 @@ var (
if err := marshaler.NewDecoder(newReader()).Decode(&{{.Body.AssignableExpr "protoReq"}}); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
{{- if and (eq (.HTTPMethod) "PATCH") (.FieldMaskField)}}
{{- if and $AllowPatchFeature (and (eq (.HTTPMethod) "PATCH") (.FieldMaskField))}}
if protoReq.{{.FieldMaskField}} != nil && len(protoReq.{{.FieldMaskField}}.GetPaths()) > 0 {
runtime.CamelCaseFieldMask(protoReq.{{.FieldMaskField}})
} {{if not (eq "*" .GetBodyFieldPath)}} else {
Expand Down
85 changes: 82 additions & 3 deletions protoc-gen-grpc-gateway/gengateway/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func TestApplyTemplateHeader(t *testing.T) {
},
},
}
got, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler"}, descriptor.NewRegistry())
got, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler", AllowPatchFeature: true}, descriptor.NewRegistry())
if err != nil {
t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
return
Expand Down Expand Up @@ -222,7 +222,7 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) {
},
},
}
got, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler"}, descriptor.NewRegistry())
got, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler", AllowPatchFeature: true}, descriptor.NewRegistry())
if err != nil {
t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
return
Expand Down Expand Up @@ -383,7 +383,7 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) {
},
},
}
got, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler"}, descriptor.NewRegistry())
got, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler", AllowPatchFeature: true}, descriptor.NewRegistry())
if err != nil {
t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
return
Expand All @@ -402,3 +402,82 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) {
}
}
}

func TestAllowPatchFeature(t *testing.T) {
updateMaskDesc := &protodescriptor.FieldDescriptorProto{
Name: proto.String("UpdateMask"),
Label: protodescriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
Type: protodescriptor.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
TypeName: proto.String(".google.protobuf.FieldMask"),
Number: proto.Int32(1),
}
msgdesc := &protodescriptor.DescriptorProto{
Name: proto.String("ExampleMessage"),
Field: []*protodescriptor.FieldDescriptorProto{updateMaskDesc},
}
meth := &protodescriptor.MethodDescriptorProto{
Name: proto.String("Example"),
InputType: proto.String("ExampleMessage"),
OutputType: proto.String("ExampleMessage"),
}
svc := &protodescriptor.ServiceDescriptorProto{
Name: proto.String("ExampleService"),
Method: []*protodescriptor.MethodDescriptorProto{meth},
}
msg := &descriptor.Message{
DescriptorProto: msgdesc,
}
updateMaskField := &descriptor.Field{
Message: msg,
FieldDescriptorProto: updateMaskDesc,
}
msg.Fields = append(msg.Fields, updateMaskField)
file := descriptor.File{
FileDescriptorProto: &protodescriptor.FileDescriptorProto{
Name: proto.String("example.proto"),
Package: proto.String("example"),
MessageType: []*protodescriptor.DescriptorProto{msgdesc},
Service: []*protodescriptor.ServiceDescriptorProto{svc},
},
GoPkg: descriptor.GoPackage{
Path: "example.com/path/to/example/example.pb",
Name: "example_pb",
},
Messages: []*descriptor.Message{msg},
Services: []*descriptor.Service{
{
ServiceDescriptorProto: svc,
Methods: []*descriptor.Method{
{
MethodDescriptorProto: meth,
RequestType: msg,
ResponseType: msg,
Bindings: []*descriptor.Binding{
{
HTTPMethod: "PATCH",
Body: &descriptor.Body{FieldPath: nil},
},
},
},
},
},
},
}
want := "if protoReq.UpdateMask != nil && len(protoReq.UpdateMask.GetPaths()) > 0 {\n"
for _, allowPatchFeature := range []bool{true, false} {
got, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler", AllowPatchFeature: allowPatchFeature}, descriptor.NewRegistry())
if err != nil {
t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err)
return
}
if allowPatchFeature {
if !strings.Contains(got, want) {
t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want)
}
} else {
if strings.Contains(got, want) {
t.Errorf("applyTemplate(%#v) = %s; want to _not_ contain %s", file, got, want)
}
}
}
}
3 changes: 2 additions & 1 deletion protoc-gen-grpc-gateway/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var (
pathType = flag.String("paths", "", "specifies how the paths of generated files are structured")
allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option")
repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.")
allowPatchFeature = flag.Bool("allow_patch_feature", true, "determines whether to use PATCH feature involving update masks (using google.protobuf.FieldMask).")
versionFlag = flag.Bool("version", false, "print the current verison")
)

Expand Down Expand Up @@ -79,7 +80,7 @@ func main() {
}
}

g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType)
g := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *pathType, *allowPatchFeature)

if *grpcAPIConfiguration != "" {
if err := reg.LoadGrpcAPIServiceFromYAML(*grpcAPIConfiguration); err != nil {
Expand Down

0 comments on commit 96cb2e2

Please sign in to comment.