diff --git a/docs/docs/mapping/customizing_openapi_output.md b/docs/docs/mapping/customizing_openapi_output.md index 1ff352263ad..3a079ef0021 100644 --- a/docs/docs/mapping/customizing_openapi_output.md +++ b/docs/docs/mapping/customizing_openapi_output.md @@ -1114,6 +1114,88 @@ definitions: type: string ``` +### Deprecating parameters -{% endraw %} +With the `enable_field_deprecation` option, OpenAPI parameters will be marked as deprecated based on the protobuf `deprecated` field option. Allowed values are: `true`, `false`. + +For example, if you are using `buf`: +```yaml +version: v1 +plugins: + - name: openapiv2 + out: . + opt: + - enable_field_deprecation=true +``` + +or with `protoc` + +```sh +protoc --openapiv2_out=. --openapiv2_opt=enable_field_deprecation=true ./path/to/file.proto +``` + +Input example: + +```protobuf +message SearchRequest { + string legacy_filter = 1 [deprecated = true]; + string query = 2; +} +``` + +Output (excerpt): + +```yaml +paths: + /v1/search: + get: + parameters: + - name: legacy_filter + in: query + required: false + type: string + deprecated: true + - name: query + in: query + required: false + type: string +``` + +If you prefer to leave the protobuf definition active, you can use the `field_configuration.deprecated` annotation on the `openapiv2_field` option instead: + +```protobuf +message SearchRequest { + string legacy_filter = 1 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Legacy filter syntax. Prefer the new 'query' field." + field_configuration: { deprecated: true } + } + ]; + string query = 2; +} +``` + +This keeps the protobuf field untouched but still emits a deprecated parameter in the generated spec: + +```yaml +paths: + /v1/search: + get: + parameters: + - name: legacy_filter + in: query + required: false + type: string + description: Legacy filter syntax. Prefer the new 'query' field. + deprecated: true + - name: query + in: query + required: false + type: string +``` + +If you set both the protobuf `deprecated = true` option and `field_configuration.deprecated`, the OpenAPI parameter is marked as deprecated regardless of the `enable_field_deprecation` option. + + +{% endraw %} diff --git a/internal/descriptor/registry.go b/internal/descriptor/registry.go index 743cea8f126..d2b71500165 100644 --- a/internal/descriptor/registry.go +++ b/internal/descriptor/registry.go @@ -167,6 +167,9 @@ type Registry struct { // enableRpcDeprecation whether to process grpc method's deprecated option enableRpcDeprecation bool + // enableFieldDeprecation whether to process proto field's deprecated option + enableFieldDeprecation bool + // expandSlashedPathPatterns, if true, for a path parameter carrying a sub-path, described via parameter pattern (i.e. // the pattern contains forward slashes), this will expand the _pattern_ into the URI and will _replace_ the parameter // with new path parameters inferred from patterns wildcards. @@ -915,6 +918,16 @@ func (r *Registry) GetEnableRpcDeprecation() bool { return r.enableRpcDeprecation } +// SetEnableFieldDeprecation sets enableFieldDeprecation +func (r *Registry) SetEnableFieldDeprecation(enable bool) { + r.enableFieldDeprecation = enable +} + +// GetEnableFieldDeprecation returns enableFieldDeprecation +func (r *Registry) GetEnableFieldDeprecation() bool { + return r.enableFieldDeprecation +} + func (r *Registry) SetExpandSlashedPathPatterns(expandSlashedPathPatterns bool) { r.expandSlashedPathPatterns = expandSlashedPathPatterns } diff --git a/protoc-gen-openapiv2/defs.bzl b/protoc-gen-openapiv2/defs.bzl index 29e548c03df..b25736c40d6 100644 --- a/protoc-gen-openapiv2/defs.bzl +++ b/protoc-gen-openapiv2/defs.bzl @@ -76,6 +76,7 @@ def _run_proto_gen_openapi( use_allof_for_refs, disable_default_responses, enable_rpc_deprecation, + enable_field_deprecation, expand_slashed_path_patterns, preserve_rpc_order, generate_x_go_type): @@ -155,6 +156,9 @@ def _run_proto_gen_openapi( if enable_rpc_deprecation: args.add("--openapiv2_opt", "enable_rpc_deprecation=true") + if enable_field_deprecation: + args.add("--openapiv2_opt", "enable_field_deprecation=true") + if expand_slashed_path_patterns: args.add("--openapiv2_opt", "expand_slashed_path_patterns=true") @@ -271,6 +275,7 @@ def _proto_gen_openapi_impl(ctx): use_allof_for_refs = ctx.attr.use_allof_for_refs, disable_default_responses = ctx.attr.disable_default_responses, enable_rpc_deprecation = ctx.attr.enable_rpc_deprecation, + enable_field_deprecation = ctx.attr.enable_field_deprecation, expand_slashed_path_patterns = ctx.attr.expand_slashed_path_patterns, preserve_rpc_order = ctx.attr.preserve_rpc_order, generate_x_go_type = ctx.attr.generate_x_go_type, @@ -434,6 +439,11 @@ protoc_gen_openapiv2 = rule( mandatory = False, doc = "whether to process grpc method's deprecated option.", ), + "enable_field_deprecation": attr.bool( + default = False, + mandatory = False, + doc = "whether to process proto field's deprecated option.", + ), "expand_slashed_path_patterns": 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 6265da8fe48..e1d9ffba96e 100644 --- a/protoc-gen-openapiv2/internal/genopenapi/template.go +++ b/protoc-gen-openapiv2/internal/genopenapi/template.go @@ -345,6 +345,11 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre } } + // verify if the field is deprecated, either via proto or annotation + protoDeprecated := field.GetOptions().GetDeprecated() && reg.GetEnableFieldDeprecation() + annotationDeprecated := getFieldConfiguration(reg, field).GetDeprecated() + deprecated := protoDeprecated || annotationDeprecated + param := openapiParameterObject{ Description: desc, In: "query", @@ -354,6 +359,7 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre Format: schema.Format, Pattern: schema.Pattern, Required: required, + Deprecated: deprecated, UniqueItems: schema.UniqueItems, extensions: schema.extensions, Enum: schema.Enum, @@ -1454,18 +1460,26 @@ func renderServices(services []*descriptor.Service, paths *openapiPathsObject, r if regExp, ok := pathParamRegexpMap[parameterString]; ok { pattern = regExp } - if fc := getFieldConfiguration(reg, parameter.Target); fc != nil { + fc := getFieldConfiguration(reg, parameter.Target) + if fc != nil { pathParamName := fc.GetPathParamName() if pathParamName != "" && pathParamName != parameterString { pathParamNames["{"+parameterString+"}"] = "{" + pathParamName + "}" parameterString, _, _ = strings.Cut(pathParamName, "=") } } + + // verify if the parameter is deprecated, either via proto or annotation + protoDeprecated := parameter.Target.GetOptions().GetDeprecated() && reg.GetEnableFieldDeprecation() + annotationDeprecated := fc.GetDeprecated() + deprecated := protoDeprecated || annotationDeprecated + parameters = append(parameters, openapiParameterObject{ Name: parameterString, Description: desc, In: "path", Required: true, + Deprecated: deprecated, Default: defaultValue, // Parameters in gRPC-Gateway can only be strings? Type: paramType, diff --git a/protoc-gen-openapiv2/internal/genopenapi/template_test.go b/protoc-gen-openapiv2/internal/genopenapi/template_test.go index a766a852430..a79730ae724 100644 --- a/protoc-gen-openapiv2/internal/genopenapi/template_test.go +++ b/protoc-gen-openapiv2/internal/genopenapi/template_test.go @@ -1326,6 +1326,181 @@ func TestMessageToQueryParametersWithRequiredField(t *testing.T) { } } +func TestMessageToQueryParametersWithDeprecatedField(t *testing.T) { + annotationOptions := func() *descriptorpb.FieldOptions { + opts := &descriptorpb.FieldOptions{} + proto.SetExtension(opts, openapi_options.E_Openapiv2Field, &openapi_options.JSONSchema{ + FieldConfiguration: &openapi_options.JSONSchema_FieldConfiguration{ + Deprecated: true, + }, + }) + return opts + } + + type test struct { + MsgDescs []*descriptorpb.DescriptorProto + Message string + Params []openapiParameterObject + enableFieldDeprecation bool + } + + tests := []test{ + { + MsgDescs: []*descriptorpb.DescriptorProto{ + { + Name: proto.String("ExampleMessage"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("deprecated_via_proto"), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + Options: &descriptorpb.FieldOptions{ + Deprecated: proto.Bool(true), + }, + }, + { + Name: proto.String("deprecated_via_annotation"), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(2), + Options: annotationOptions(), + }, + { + Name: proto.String("active_field"), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(3), + }, + }, + }, + }, + Message: "ExampleMessage", + enableFieldDeprecation: true, + Params: []openapiParameterObject{ + { + Name: "deprecated_via_proto", + In: "query", + Required: false, + Type: "string", + Deprecated: true, + }, + { + Name: "deprecated_via_annotation", + In: "query", + Required: false, + Type: "string", + Deprecated: true, + }, + { + Name: "active_field", + In: "query", + Required: false, + Type: "string", + }, + }, + }, + { + MsgDescs: []*descriptorpb.DescriptorProto{ + { + Name: proto.String("ExampleMessage"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("deprecated_via_proto"), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + Options: &descriptorpb.FieldOptions{ + Deprecated: proto.Bool(true), + }, + }, + { + Name: proto.String("deprecated_via_annotation"), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(2), + Options: annotationOptions(), + }, + { + Name: proto.String("active_field"), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(3), + }, + }, + }, + }, + Message: "ExampleMessage", + enableFieldDeprecation: false, + Params: []openapiParameterObject{ + { + Name: "deprecated_via_proto", + In: "query", + Required: false, + Type: "string", + Deprecated: false, + }, + { + Name: "deprecated_via_annotation", + In: "query", + Required: false, + Type: "string", + Deprecated: true, + }, + { + Name: "active_field", + In: "query", + Required: false, + Type: "string", + }, + }, + }, + } + + // Enable or disable proto-field deprecation per test case before loading descriptors. + for _, test := range tests { + reg := descriptor.NewRegistry() + reg.SetEnableFieldDeprecation(test.enableFieldDeprecation) + msgs := []*descriptor.Message{} + for _, msgdesc := range test.MsgDescs { + msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) + } + file := descriptor.File{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + Dependency: []string{}, + MessageType: test.MsgDescs, + Service: []*descriptorpb.ServiceDescriptorProto{}, + Options: &descriptorpb.FileOptions{ + GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"), + }, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: msgs, + } + err := reg.Load(&pluginpb.CodeGeneratorRequest{ + ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, + }) + if err != nil { + t.Fatalf("failed to load code generator request: %v", err) + } + + message, err := reg.LookupMsg("", ".example."+test.Message) + if err != nil { + t.Fatalf("failed to lookup message: %s", err) + } + params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil, "") + if err != nil { + t.Fatalf("failed to convert message to query parameters: %s", err) + } + for i := range params { + params[i].Items = nil + } + if !reflect.DeepEqual(params, test.Params) { + t.Errorf("expected %v, got %v", test.Params, params) + } + } +} + func TestMessageToQueryParametersWithEnumFieldOption(t *testing.T) { type test struct { MsgDescs []*descriptorpb.DescriptorProto @@ -11357,6 +11532,178 @@ func TestRenderServicesOptionDeprecated(t *testing.T) { } } +func TestRenderServicesMarksDeprecatedParameters(t *testing.T) { + cases := []struct { + name string + fieldDeprecated bool + enableFieldDeprecation bool + fieldConfigDeprecated bool + expectedDeprecated bool + }{ + { + name: "proto field deprecated but feature disabled", + fieldDeprecated: true, + enableFieldDeprecation: false, + expectedDeprecated: false, + }, + { + name: "proto field deprecated with feature enabled", + fieldDeprecated: true, + enableFieldDeprecation: true, + expectedDeprecated: true, + }, + + { + name: "field config annotation deprecated", + fieldConfigDeprecated: true, + expectedDeprecated: true, + }, + { + name: "non-deprecated field", + expectedDeprecated: false, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + var fieldOptions *descriptorpb.FieldOptions + if tc.fieldDeprecated || tc.fieldConfigDeprecated { + fieldOptions = &descriptorpb.FieldOptions{} + if tc.fieldDeprecated { + fieldOptions.Deprecated = proto.Bool(true) + } + if tc.fieldConfigDeprecated { + proto.SetExtension(fieldOptions, openapi_options.E_Openapiv2Field, &openapi_options.JSONSchema{ + FieldConfiguration: &openapi_options.JSONSchema_FieldConfiguration{ + Deprecated: true, + }, + }) + } + } + fieldDesc := &descriptorpb.FieldDescriptorProto{ + Name: proto.String("name"), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + Number: proto.Int32(1), + Options: fieldOptions, + JsonName: proto.String("name"), + } + reqMsgDesc := &descriptorpb.DescriptorProto{ + Name: proto.String("ExampleRequest"), + Field: []*descriptorpb.FieldDescriptorProto{fieldDesc}, + } + respMsgDesc := &descriptorpb.DescriptorProto{ + Name: proto.String("ExampleResponse"), + } + + reqMsg := &descriptor.Message{ + DescriptorProto: reqMsgDesc, + } + respMsg := &descriptor.Message{ + DescriptorProto: respMsgDesc, + } + field := &descriptor.Field{ + FieldDescriptorProto: fieldDesc, + Message: reqMsg, + } + reqMsg.Fields = []*descriptor.Field{field} + + method := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("GetExample"), + InputType: proto.String(".example.ExampleRequest"), + OutputType: proto.String(".example.ExampleResponse"), + } + + compiler, err := httprule.Parse("/v1/{name}") + if err != nil { + t.Fatalf("failed to parse path template: %v", err) + } + pathTemplate := compiler.Compile() + + binding := &descriptor.Binding{ + HTTPMethod: "GET", + PathTmpl: pathTemplate, + PathParams: []descriptor.Parameter{ + { + Target: field, + FieldPath: descriptor.FieldPath{ + { + Name: "name", + Target: field, + }, + }, + }, + }, + } + + methodDesc := &descriptor.Method{ + MethodDescriptorProto: method, + RequestType: reqMsg, + ResponseType: respMsg, + Bindings: []*descriptor.Binding{binding}, + } + + service := &descriptorpb.ServiceDescriptorProto{ + Name: proto.String("ExampleService"), + Method: []*descriptorpb.MethodDescriptorProto{method}, + } + + serviceDesc := &descriptor.Service{ + ServiceDescriptorProto: service, + Methods: []*descriptor.Method{methodDesc}, + } + + file := descriptor.File{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, + Name: proto.String("example.proto"), + Package: proto.String("example"), + MessageType: []*descriptorpb.DescriptorProto{reqMsgDesc, respMsgDesc}, + Service: []*descriptorpb.ServiceDescriptorProto{service}, + Options: &descriptorpb.FileOptions{ + GoPackage: proto.String("github.com/grpc-ecosystem/grpc-gateway/runtime/internal/examplepb;example"), + }, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: []*descriptor.Message{reqMsg, respMsg}, + Services: []*descriptor.Service{serviceDesc}, + } + + reg := descriptor.NewRegistry() + reg.SetEnableFieldDeprecation(tc.enableFieldDeprecation) + fileCL := crossLinkFixture(&file) + if err := reg.Load(reqFromFile(fileCL)); err != nil { + t.Fatalf("failed to load code generator request: %v", err) + } + + result, err := applyTemplate(param{File: fileCL, reg: reg}) + if err != nil { + t.Fatalf("applyTemplate(%#v) failed with %v; want success", file, err) + } + + operation := result.getPathItemObject("/v1/{name}").Get + if operation == nil { + t.Fatalf("expected GET operation to be generated for /v1/{name}") + } + found := false + for _, param := range operation.Parameters { + if param.In == "path" && param.Name == "name" { + found = true + if param.Deprecated != tc.expectedDeprecated { + t.Fatalf("expected deprecated flag to be %v, got %v", tc.expectedDeprecated, param.Deprecated) + } + } + } + if !found { + t.Fatalf("expected to find path parameter named 'name'") + } + }) + } +} + func Test_updateSwaggerObjectFromFieldBehavior(t *testing.T) { type args struct { s *openapiSchemaObject diff --git a/protoc-gen-openapiv2/internal/genopenapi/types.go b/protoc-gen-openapiv2/internal/genopenapi/types.go index db9be4ded79..ab60dca4917 100644 --- a/protoc-gen-openapiv2/internal/genopenapi/types.go +++ b/protoc-gen-openapiv2/internal/genopenapi/types.go @@ -149,6 +149,7 @@ type openapiParameterObject struct { Description string `json:"description,omitempty" yaml:"description,omitempty"` In string `json:"in,omitempty" yaml:"in,omitempty"` Required bool `json:"required" yaml:"required"` + Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` Type string `json:"type,omitempty" yaml:"type,omitempty"` Format string `json:"format,omitempty" yaml:"format,omitempty"` UniqueItems bool `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"` diff --git a/protoc-gen-openapiv2/main.go b/protoc-gen-openapiv2/main.go index 82062cc99f6..f8fa9a31581 100644 --- a/protoc-gen-openapiv2/main.go +++ b/protoc-gen-openapiv2/main.go @@ -50,6 +50,7 @@ var ( allowPatchFeature = flag.Bool("allow_patch_feature", true, "whether to hide update_mask fields in PATCH requests from the generated swagger file.") preserveRPCOrder = flag.Bool("preserve_rpc_order", false, "if true, will ensure the order of paths emitted in openapi swagger files mirror the order of RPC methods found in proto files. If false, emitted paths will be ordered alphabetically.") enableRpcDeprecation = flag.Bool("enable_rpc_deprecation", false, "whether to process grpc method's deprecated option.") + enableFieldDeprecation = flag.Bool("enable_field_deprecation", false, "whether to process proto field's deprecated option.") expandSlashedPathPatterns = flag.Bool("expand_slashed_path_patterns", false, "if set, expands path parameters with URI sub-paths into the URI. For example, \"/v1/{name=projects/*}/resource\" becomes \"/v1/projects/{project}/resource\".") useProto3FieldSemantics = flag.Bool("use_proto3_field_semantics", false, "if set, uses proto3 field semantics for the OpenAPI schema. This means that fields are required by default.") generateXGoType = flag.Bool("generate_x_go_type", false, "if set, generates x-go-type extension using the go_package option from proto files") @@ -177,6 +178,7 @@ func main() { reg.SetAllowPatchFeature(*allowPatchFeature) reg.SetPreserveRPCOrder(*preserveRPCOrder) reg.SetEnableRpcDeprecation(*enableRpcDeprecation) + reg.SetEnableFieldDeprecation(*enableFieldDeprecation) reg.SetExpandSlashedPathPatterns(*expandSlashedPathPatterns) reg.SetGenerateXGoType(*generateXGoType) diff --git a/protoc-gen-openapiv2/options/openapiv2.pb.go b/protoc-gen-openapiv2/options/openapiv2.pb.go index 3a34e664e0a..5121dce386c 100644 --- a/protoc-gen-openapiv2/options/openapiv2.pb.go +++ b/protoc-gen-openapiv2/options/openapiv2.pb.go @@ -3476,6 +3476,9 @@ type JSONSchema_FieldConfiguration struct { // parameter. Use this to avoid having auto generated path parameter names // for overlapping paths. PathParamName string `protobuf:"bytes,47,opt,name=path_param_name,json=pathParamName,proto3" json:"path_param_name,omitempty"` + // Declares this field to be deprecated. Allows for the generated OpenAPI + // parameter to be marked as deprecated without affecting the proto field. + Deprecated bool `protobuf:"varint,49,opt,name=deprecated,proto3" json:"deprecated,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3512,10 +3515,21 @@ func (x *JSONSchema_FieldConfiguration) GetPathParamName() string { return "" } +func (x *JSONSchema_FieldConfiguration) GetDeprecated() bool { + if x != nil { + return x.Deprecated + } + return false +} + func (x *JSONSchema_FieldConfiguration) SetPathParamName(v string) { x.PathParamName = v } +func (x *JSONSchema_FieldConfiguration) SetDeprecated(v bool) { + x.Deprecated = v +} + type JSONSchema_FieldConfiguration_builder struct { _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. @@ -3524,6 +3538,9 @@ type JSONSchema_FieldConfiguration_builder struct { // parameter. Use this to avoid having auto generated path parameter names // for overlapping paths. PathParamName string + // Declares this field to be deprecated. Allows for the generated OpenAPI + // parameter to be marked as deprecated without affecting the proto field. + Deprecated bool } func (b0 JSONSchema_FieldConfiguration_builder) Build() *JSONSchema_FieldConfiguration { @@ -3531,6 +3548,7 @@ func (b0 JSONSchema_FieldConfiguration_builder) Build() *JSONSchema_FieldConfigu b, x := &b0, m0 _, _ = b, x x.PathParamName = b.PathParamName + x.Deprecated = b.Deprecated return m0 } @@ -3904,7 +3922,7 @@ var file_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd7, + 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf7, 0x0a, 0x0a, 0x0a, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, @@ -3968,11 +3986,13 @@ var file_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3c, 0x0a, 0x12, + 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x5c, 0x0a, 0x12, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x74, - 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, + 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, + 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x31, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, + 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, diff --git a/protoc-gen-openapiv2/options/openapiv2.proto b/protoc-gen-openapiv2/options/openapiv2.proto index 5313f0818ae..444a5687a51 100644 --- a/protoc-gen-openapiv2/options/openapiv2.proto +++ b/protoc-gen-openapiv2/options/openapiv2.proto @@ -612,6 +612,9 @@ message JSONSchema { // parameter. Use this to avoid having auto generated path parameter names // for overlapping paths. string path_param_name = 47; + // Declares this field to be deprecated. Allows for the generated OpenAPI + // parameter to be marked as deprecated without affecting the proto field. + bool deprecated = 49; } // Custom properties that start with "x-" such as "x-foo" used to describe // extra functionality that is not covered by the standard OpenAPI Specification. diff --git a/protoc-gen-openapiv2/options/openapiv2_protoopaque.pb.go b/protoc-gen-openapiv2/options/openapiv2_protoopaque.pb.go index 1f0e0c26916..5316ed61923 100644 --- a/protoc-gen-openapiv2/options/openapiv2_protoopaque.pb.go +++ b/protoc-gen-openapiv2/options/openapiv2_protoopaque.pb.go @@ -3268,6 +3268,7 @@ func (b0 Scopes_builder) Build() *Scopes { type JSONSchema_FieldConfiguration struct { state protoimpl.MessageState `protogen:"opaque.v1"` xxx_hidden_PathParamName string `protobuf:"bytes,47,opt,name=path_param_name,json=pathParamName,proto3" json:"path_param_name,omitempty"` + xxx_hidden_Deprecated bool `protobuf:"varint,49,opt,name=deprecated,proto3" json:"deprecated,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3304,10 +3305,21 @@ func (x *JSONSchema_FieldConfiguration) GetPathParamName() string { return "" } +func (x *JSONSchema_FieldConfiguration) GetDeprecated() bool { + if x != nil { + return x.xxx_hidden_Deprecated + } + return false +} + func (x *JSONSchema_FieldConfiguration) SetPathParamName(v string) { x.xxx_hidden_PathParamName = v } +func (x *JSONSchema_FieldConfiguration) SetDeprecated(v bool) { + x.xxx_hidden_Deprecated = v +} + type JSONSchema_FieldConfiguration_builder struct { _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. @@ -3316,6 +3328,9 @@ type JSONSchema_FieldConfiguration_builder struct { // parameter. Use this to avoid having auto generated path parameter names // for overlapping paths. PathParamName string + // Declares this field to be deprecated. Allows for the generated OpenAPI + // parameter to be marked as deprecated without affecting the proto field. + Deprecated bool } func (b0 JSONSchema_FieldConfiguration_builder) Build() *JSONSchema_FieldConfiguration { @@ -3323,6 +3338,7 @@ func (b0 JSONSchema_FieldConfiguration_builder) Build() *JSONSchema_FieldConfigu b, x := &b0, m0 _, _ = b, x x.xxx_hidden_PathParamName = b.PathParamName + x.xxx_hidden_Deprecated = b.Deprecated return m0 } @@ -3696,7 +3712,7 @@ var file_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd7, + 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf7, 0x0a, 0x0a, 0x0a, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, @@ -3760,11 +3776,13 @@ var file_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3c, 0x0a, 0x12, + 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x5c, 0x0a, 0x12, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x74, - 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, + 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, + 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x31, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, + 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x1a, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,