diff --git a/docs/docs/mapping/customizing_openapi_output.md b/docs/docs/mapping/customizing_openapi_output.md index baa5087f571..5ed03f7f132 100644 --- a/docs/docs/mapping/customizing_openapi_output.md +++ b/docs/docs/mapping/customizing_openapi_output.md @@ -578,4 +578,67 @@ definitions: type: string ``` +### Disable service tag generation + +By default service tags are generated for backend services, but it is possible to disable it using the `disable_service_tags` option. Allowed values are: `true`, `false`. + +For example, if you are using `buf`: +```yaml +version: v1 +plugins: + - name: openapiv2 + out: . + opt: + - disable_service_tags=true +``` + +or with `protoc` + +```sh +protoc --openapiv2_out=. --openapiv2_opt=disable_service_tags=true ./path/to/file.proto +``` + +Input example: +```protobuf +syntax = "proto3"; + +package helloproto.v1; +option go_package = "helloproto/v1;helloproto"; + +import "google/api/annotations.proto"; + +service EchoService { + rpc Hello(HelloReq) returns (HelloResp) { + option (google.api.http) = { + get: "/api/hello" + }; + } +} + +message HelloReq { + string name = 1; +} + +message HelloResp { + string message = 1; +} +``` + +Output (tags object are not generated): +```yaml +swagger: "2.0" +info: + title: helloproto/v1/example.proto + version: version not set +consumes: +- application/json +produces: +- application/json +paths: + /api/hello: + get: + operationId: EchoService_Hello +... +``` + {% endraw %} diff --git a/internal/descriptor/registry.go b/internal/descriptor/registry.go index cd2c128f3fb..8a7142f1393 100644 --- a/internal/descriptor/registry.go +++ b/internal/descriptor/registry.go @@ -127,6 +127,10 @@ type Registry struct { // annotationMap is used to check for duplicate HTTP annotations annotationMap map[annotationIdentifier]struct{} + + // disableServiceTags disables the generation of service tags. + // This is useful if you do not want to expose the names of your backend grpc services. + disableServiceTags bool } type repeatedFieldSeparator struct { @@ -737,3 +741,13 @@ func (r *Registry) CheckDuplicateAnnotation(httpMethod string, httpTemplate stri r.annotationMap[a] = struct{}{} return nil } + +// SetDisableServiceTags sets disableServiceTags +func (r *Registry) SetDisableServiceTags(use bool) { + r.disableServiceTags = use +} + +// GetDisableServiceTags returns disableServiceTags +func (r *Registry) GetDisableServiceTags() bool { + return r.disableServiceTags +} diff --git a/protoc-gen-openapiv2/defs.bzl b/protoc-gen-openapiv2/defs.bzl index b5805e9a740..2ecb18716b6 100644 --- a/protoc-gen-openapiv2/defs.bzl +++ b/protoc-gen-openapiv2/defs.bzl @@ -61,6 +61,7 @@ def _run_proto_gen_openapi( openapi_naming_strategy, use_go_templates, disable_default_errors, + disable_service_tags, enums_as_ints, omit_enum_default_value, output_format, @@ -112,6 +113,9 @@ def _run_proto_gen_openapi( if disable_default_errors: args.add("--openapiv2_opt", "disable_default_errors=true") + if disable_service_tags: + args.add("--openapiv2_opt", "disable_service_tags=true") + if enums_as_ints: args.add("--openapiv2_opt", "enums_as_ints=true") @@ -220,6 +224,7 @@ def _proto_gen_openapi_impl(ctx): openapi_naming_strategy = ctx.attr.openapi_naming_strategy, use_go_templates = ctx.attr.use_go_templates, disable_default_errors = ctx.attr.disable_default_errors, + disable_service_tags = ctx.attr.disable_service_tags, enums_as_ints = ctx.attr.enums_as_ints, omit_enum_default_value = ctx.attr.omit_enum_default_value, output_format = ctx.attr.output_format, @@ -301,6 +306,12 @@ protoc_gen_openapiv2 = rule( doc = "if set, disables generation of default errors." + " This is useful if you have defined custom error handling", ), + "disable_service_tags": attr.bool( + default = False, + mandatory = False, + doc = "if set, disables generation of service tags." + + " This is useful if you do not want to expose the names of your backend grpc services.", + ), "enums_as_ints": attr.bool( default = False, mandatory = False, diff --git a/protoc-gen-openapiv2/internal/genopenapi/template.go b/protoc-gen-openapiv2/internal/genopenapi/template.go index 0c1fc244c3f..9c49d09d9b7 100644 --- a/protoc-gen-openapiv2/internal/genopenapi/template.go +++ b/protoc-gen-openapiv2/internal/genopenapi/template.go @@ -1589,7 +1589,10 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { if err := renderServices(p.Services, s.Paths, p.reg, requestResponseRefs, customRefs, p.Messages); err != nil { panic(err) } - s.Tags = append(s.Tags, renderServiceTags(p.Services, p.reg)...) + + if !p.reg.GetDisableServiceTags() { + s.Tags = append(s.Tags, renderServiceTags(p.Services, p.reg)...) + } messages := messageMap{} streamingMessages := messageMap{} diff --git a/protoc-gen-openapiv2/internal/genopenapi/template_test.go b/protoc-gen-openapiv2/internal/genopenapi/template_test.go index 329ce969180..7369fe0886a 100644 --- a/protoc-gen-openapiv2/internal/genopenapi/template_test.go +++ b/protoc-gen-openapiv2/internal/genopenapi/template_test.go @@ -1614,6 +1614,18 @@ func TestApplyTemplateOpenAPIConfigFromYAML(t *testing.T) { t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) } + reg.SetDisableServiceTags(true) + + res, err := applyTemplate(param{File: fileCL, reg: reg}) + if err != nil { + t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) + return + } + + if got, want := len(res.Tags), 0; got != want { + t.Fatalf("len(applyTemplate(%#v).Tags) = %d want to be %d", file, got, want) + } + // If there was a failure, print out the input and the json result for debugging. if t.Failed() { t.Errorf("had: %s", file) diff --git a/protoc-gen-openapiv2/main.go b/protoc-gen-openapiv2/main.go index ec4e5c62750..0e3907c7112 100644 --- a/protoc-gen-openapiv2/main.go +++ b/protoc-gen-openapiv2/main.go @@ -40,6 +40,7 @@ var ( omitEnumDefaultValue = flag.Bool("omit_enum_default_value", false, "if set, omit default enum value") outputFormat = flag.String("output_format", string(genopenapi.FormatJSON), fmt.Sprintf("output content format. Allowed values are: `%s`, `%s`", genopenapi.FormatJSON, genopenapi.FormatYAML)) visibilityRestrictionSelectors = utilities.StringArrayFlag(flag.CommandLine, "visibility_restriction_selectors", "list of `google.api.VisibilityRule` visibility labels to include in the generated output when a visibility annotation is defined. Repeat this option to supply multiple values. Elements without visibility annotations are unaffected by this setting.") + disableServiceTags = flag.Bool("disable_service_tags", false, "if set, disables generation of service tags. This is useful if you do not want to expose the names of your backend grpc services.") ) // Variables set by goreleaser at build time @@ -124,6 +125,7 @@ func main() { reg.SetRecursiveDepth(*recursiveDepth) reg.SetOmitEnumDefaultValue(*omitEnumDefaultValue) reg.SetVisibilityRestrictionSelectors(*visibilityRestrictionSelectors) + reg.SetDisableServiceTags(*disableServiceTags) if err := reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator); err != nil { emitError(err) return