From 091b25114fc0d07dd28abf0e28c9c2e2be28eadd Mon Sep 17 00:00:00 2001 From: Sasha Melentyev Date: Tue, 16 Apr 2024 11:22:44 +0300 Subject: [PATCH] feat: add deprecated method (#148) Signed-off-by: Sasha Melentyev --- example/openapi.yaml | 1 + example/service.proto | 1 + internal/gen/generator.go | 6 +++-- internal/gen/schema.go | 53 ++++++++++++++++++++++----------------- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/example/openapi.yaml b/example/openapi.yaml index 61ca7b4..2705971 100644 --- a/example/openapi.yaml +++ b/example/openapi.yaml @@ -63,6 +63,7 @@ paths: application/json: schema: $ref: '#/components/schemas/Item' + deprecated: true put: operationId: updateItem parameters: diff --git a/example/service.proto b/example/service.proto index a504319..c2aaaf8 100644 --- a/example/service.proto +++ b/example/service.proto @@ -24,6 +24,7 @@ service Service { option (google.api.http) = { get: "/api/v1/items/{id}" }; + option deprecated = true; } rpc UpdateItem(UpdateItemRequest) returns (Item) { option (google.api.http) = { diff --git a/internal/gen/generator.go b/internal/gen/generator.go index 8488c8c..ac894ec 100644 --- a/internal/gen/generator.go +++ b/internal/gen/generator.go @@ -38,7 +38,8 @@ func NewGenerator(files []*protogen.File, opts ...GeneratorOption) (*Generator, for _, s := range f.Services { for _, m := range s.Methods { for _, rule := range collectRules(m.Desc.Options()) { - tmpl, op, err := g.mkMethod(rule, m) + isDeprecated := isDeprecatedMethod(m.Desc.Options()) + tmpl, op, err := g.mkMethod(rule, m, isDeprecated) if err != nil { return nil, errors.Wrapf(err, "make method %s => %s %s mapping", m.Desc.FullName(), rule.Method, rule.Path) } @@ -131,11 +132,12 @@ func (g *Generator) init() { g.descriptorNames = make(map[string]struct{}) } -func (g *Generator) mkMethod(rule HTTPRule, m *protogen.Method) (string, *ogen.Operation, error) { +func (g *Generator) mkMethod(rule HTTPRule, m *protogen.Method, deprecated bool) (string, *ogen.Operation, error) { op := ogen.NewOperation() if !rule.Additional { op.SetOperationID(LowerCamelCase(m.Desc.Name())) } + op.Deprecated = deprecated tmpl, err := g.mkInput(rule, m, op) if err != nil { diff --git a/internal/gen/schema.go b/internal/gen/schema.go index a699e91..f0bb909 100644 --- a/internal/gen/schema.go +++ b/internal/gen/schema.go @@ -127,33 +127,33 @@ func (g *Generator) mkFieldSchema(fd protoreflect.FieldDescriptor, description s switch kind := fd.Kind(); kind { case protoreflect.BoolKind: - return ogen.NewSchema().SetType("boolean").SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)), nil + return ogen.NewSchema().SetType("boolean").SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)), nil case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: - return ogen.NewSchema().SetType("integer").SetFormat("int32").SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)), nil + return ogen.NewSchema().SetType("integer").SetFormat("int32").SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)), nil case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: - return ogen.NewSchema().SetType("integer").SetFormat("uint32").SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)), nil + return ogen.NewSchema().SetType("integer").SetFormat("uint32").SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)), nil case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: - return ogen.NewSchema().SetType("integer").SetFormat("int64").SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)), nil + return ogen.NewSchema().SetType("integer").SetFormat("int64").SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)), nil case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: - return ogen.NewSchema().SetType("integer").SetFormat("uint64").SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)), nil + return ogen.NewSchema().SetType("integer").SetFormat("uint64").SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)), nil case protoreflect.FloatKind: - return ogen.NewSchema().SetType("number").SetFormat("float").SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)), nil + return ogen.NewSchema().SetType("number").SetFormat("float").SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)), nil case protoreflect.DoubleKind: - return ogen.NewSchema().SetType("number").SetFormat("double").SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)), nil + return ogen.NewSchema().SetType("number").SetFormat("double").SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)), nil case protoreflect.StringKind: - schema := ogen.NewSchema().SetType("string").SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)) + schema := ogen.NewSchema().SetType("string").SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)) setFieldFormat(schema, fd.Options()) return schema, nil case protoreflect.BytesKind: @@ -162,10 +162,10 @@ func (g *Generator) mkFieldSchema(fd protoreflect.FieldDescriptor, description s // https://github.com/protocolbuffers/protobuf-go/blob/f221882bfb484564f1714ae05f197dea2c76898d/encoding/protojson/encode.go#L287-L288 // // Do the same here. - return ogen.NewSchema().SetType("string").SetFormat("base64").SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)), nil + return ogen.NewSchema().SetType("string").SetFormat("base64").SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)), nil case protoreflect.EnumKind: - return ogen.NewSchema().SetRef(descriptorRef(fd.Enum())).SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)), nil + return ogen.NewSchema().SetRef(descriptorRef(fd.Enum())).SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)), nil case protoreflect.MessageKind: msg := fd.Message() @@ -199,7 +199,7 @@ func (g *Generator) mkFieldSchema(fd protoreflect.FieldDescriptor, description s } // User-defined type. - return ogen.NewSchema().SetRef(descriptorRef(msg)).SetDeprecated(isDeprecated(fd.Options())).SetDescription(mkDescription(description)), nil + return ogen.NewSchema().SetRef(descriptorRef(msg)).SetDeprecated(isDeprecatedField(fd.Options())).SetDescription(mkDescription(description)), nil } default: // protoreflect.GroupKind return nil, errors.Errorf("unsupported kind: %s", kind) @@ -211,38 +211,38 @@ func (g *Generator) mkWellKnownPrimitive(msg protoreflect.MessageDescriptor) (s case "google.protobuf": switch msg.Name() { case "BoolValue": - return ogen.NewSchema().SetType("boolean").SetNullable(true).SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("boolean").SetNullable(true).SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "Int32Value": - return ogen.NewSchema().SetType("integer").SetFormat("int32").SetNullable(true).SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("integer").SetFormat("int32").SetNullable(true).SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "UInt32Value": - return ogen.NewSchema().SetType("integer").SetFormat("uint32").SetNullable(true).SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("integer").SetFormat("uint32").SetNullable(true).SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "Int64Value": - return ogen.NewSchema().SetType("integer").SetFormat("int64").SetNullable(true).SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("integer").SetFormat("int64").SetNullable(true).SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "UInt64Value": - return ogen.NewSchema().SetType("integer").SetFormat("uint64").SetNullable(true).SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("integer").SetFormat("uint64").SetNullable(true).SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "FloatValue": - return ogen.NewSchema().SetType("number").SetFormat("float").SetNullable(true).SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("number").SetFormat("float").SetNullable(true).SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "DoubleValue": - return ogen.NewSchema().SetType("number").SetFormat("double").SetNullable(true).SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("number").SetFormat("double").SetNullable(true).SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "StringValue": - return ogen.NewSchema().SetType("string").SetNullable(true).SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("string").SetNullable(true).SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "BytesValue": // Go's protojson encodes binary data as base64 string. // // https://github.com/protocolbuffers/protobuf-go/blob/f221882bfb484564f1714ae05f197dea2c76898d/encoding/protojson/encode.go#L287-L288 // // Do the same here. - return ogen.NewSchema().SetType("string").SetFormat("base64").SetNullable(true).SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("string").SetFormat("base64").SetNullable(true).SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "Duration": - return ogen.NewSchema().SetType("string").SetFormat("duration").SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("string").SetFormat("duration").SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "Timestamp": // FIXME(tdakkota): protojson uses RFC 3339 - return ogen.NewSchema().SetType("string").SetFormat("date-time").SetDeprecated(isDeprecated(msg.Options())), true, nil + return ogen.NewSchema().SetType("string").SetFormat("date-time").SetDeprecated(isDeprecatedField(msg.Options())), true, nil case "Any", "Value", "NullValue", @@ -283,7 +283,14 @@ func schemaRef(s string) string { return fmt.Sprintf("#/components/schemas/%s", s) } -func isDeprecated(opts protoreflect.ProtoMessage) bool { +func isDeprecatedMethod(opts protoreflect.ProtoMessage) bool { + if opts, ok := opts.(*descriptorpb.MethodOptions); ok && opts != nil && opts.Deprecated != nil { + return *opts.Deprecated + } + return false +} + +func isDeprecatedField(opts protoreflect.ProtoMessage) bool { if opts, ok := opts.(*descriptorpb.FieldOptions); ok && opts != nil && opts.Deprecated != nil { return *opts.Deprecated }