Repository: googleapis/gapic-generator-go
Pull request #1199 (2022-12-07 23:27:51)

fix(gengapic): only gen REST client for RESTable services
This is a fix, and introduces the possibility of a breaking change, in generation of clients when `rest` is a selected transport. If a proto service being generated doesn't have any RPCs with `google.api.http` annotations i.e. they are not "REST-able", then a REST client is not generated for the proto service.

I've added a sanity check but based on where the code is placed it is really hard to test without setting up the entire generator in code. I have tested this in local generation and with the known example added to `test.sh`.


Patch:
diff --git a/internal/gengapic/gengapic.go b/internal/gengapic/gengapic.go
index 0c65309..2278bc2 100644
--- a/internal/gengapic/gengapic.go
+++ b/internal/gengapic/gengapic.go
@@ -101,6 +101,13 @@ func Gen(genReq *plugin.CodeGeneratorRequest) (*plugin.CodeGeneratorResponse, er
 		outFile = filepath.Join(g.opts.outDir, outFile)
 
 		g.reset()
+		// If the service has no REST-able RPCs, then a REGAPIC should not be
+		// generated for it, even if REST is an enabled transport.
+		transports := g.opts.transports
+		hasREST := hasRESTMethod(s)
+		if !hasREST {
+			g.opts.transports = []transport{grpc}
+		}
 		if err := g.gen(s); err != nil {
 			return &g.resp, err
 		}
@@ -112,6 +119,12 @@ func Gen(genReq *plugin.CodeGeneratorRequest) (*plugin.CodeGeneratorResponse, er
 		}
 		g.imports[pbinfo.ImportSpec{Name: g.opts.pkgName, Path: g.opts.pkgPath}] = true
 		g.commit(outFile+"_client_example_test.go", g.opts.pkgName+"_test")
+
+		// Replace original set of transports for the next service that may have
+		// REST-able RPCs.
+		if !hasREST {
+			g.opts.transports = transports
+		}
 	}
 
 	g.reset()
diff --git a/internal/gengapic/helpers.go b/internal/gengapic/helpers.go
index 2c6788b..67b1d84 100644
--- a/internal/gengapic/helpers.go
+++ b/internal/gengapic/helpers.go
@@ -122,6 +122,19 @@ func hasMethod(service *descriptor.ServiceDescriptorProto, method string) bool {
 	return false
 }
 
+// hasRESTMethod reports if there is at least one RPC on the Service that
+// has a gRPC-HTTP transcoding, or REST, annotation on it.
+func hasRESTMethod(service *descriptor.ServiceDescriptorProto) bool {
+	for _, m := range service.GetMethod() {
+		eHTTP := proto.GetExtension(m.GetOptions(), annotations.E_Http)
+		if h := eHTTP.(*annotations.HttpRule); h.GetPattern() != nil {
+			return true
+		}
+	}
+
+	return false
+}
+
 // getMethod returns the MethodDescriptorProto for the given service RPC and simple method name.
 func getMethod(service *descriptor.ServiceDescriptorProto, method string) *descriptor.MethodDescriptorProto {
 	for _, m := range service.GetMethod() {


Test patch:
diff --git a/internal/gengapic/helpers_test.go b/internal/gengapic/helpers_test.go
index 467fea6..ab0bbc3 100644
--- a/internal/gengapic/helpers_test.go
+++ b/internal/gengapic/helpers_test.go
@@ -272,3 +272,26 @@ func TestGetHeaderName(t *testing.T) {
 		}
 	}
 }
+
+func TestHasRESTMethod(t *testing.T) {
+	for _, tst := range []struct {
+		name string
+		want bool
+	}{
+		{"has_rest_method", true},
+		{"does_not_have_rest_method", false},
+	} {
+		opts := &descriptor.MethodOptions{}
+		if tst.want {
+			proto.SetExtension(opts, annotations.E_Http, &annotations.HttpRule{Pattern: &annotations.HttpRule_Get{Get: "/foo"}})
+		}
+		s := &descriptor.ServiceDescriptorProto{
+			Method: []*descriptor.MethodDescriptorProto{
+				{Options: opts},
+			},
+		}
+		if got := hasRESTMethod(s); got != tst.want {
+			t.Fatalf("%s: expected %v, got %v", tst.name, tst.want, got)
+		}
+	}
+}
diff --git a/test.sh b/test.sh
index 66b831f..90af934 100755
--- a/test.sh
+++ b/test.sh
@@ -51,6 +51,9 @@ generate --go_gapic_opt 'go-gapic-package=cloud.google.com/go/storage/internal/a
 echo "Generating Cloud Retail v2"
 generate --go_gapic_opt 'go-gapic-package=cloud.google.com/go/retail/apiv2;retail,transport=rest' $GOOGLEAPIS/google/cloud/retail/v2/*.proto
 
+echo "Generating Apigee Connect v1 - Dual Transport, partial REGAPIC"
+generate --go_gapic_opt 'go-gapic-package=cloud.google.com/go/apigeeconnect/apiv1;apigeeconnect,transport=grpc+rest' $GOOGLEAPIS/google/cloud/apigeeconnect/v1/*.proto
+
 echo "Generation complete"
 
 echo "Running gofmt to check for syntax errors"