allow to specify external types in ref openapi annotation #35

Merged
vtolstov merged 1 commits from protofix into master 2022-02-28 15:51:19 +03:00
4 changed files with 83 additions and 27 deletions

2
go.mod
View File

@ -4,7 +4,7 @@ go 1.16
require ( require (
github.com/fatih/structtag v1.2.0 github.com/fatih/structtag v1.2.0
go.unistack.org/micro-proto/v3 v3.2.3 go.unistack.org/micro-proto/v3 v3.2.5
golang.org/x/tools v0.1.9 golang.org/x/tools v0.1.9
google.golang.org/protobuf v1.27.1 google.golang.org/protobuf v1.27.1
) )

4
go.sum
View File

@ -68,8 +68,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.unistack.org/micro-proto/v3 v3.2.3 h1:vSRI6VoZrlv0pUdo69irHv6HbbnD+oZOGEUE/TS5XBQ= go.unistack.org/micro-proto/v3 v3.2.5 h1:qaMr9oaO8J2X9nvcZfQ+JriuEFfoMzRvFfQdKoVlWgU=
go.unistack.org/micro-proto/v3 v3.2.3/go.mod h1:ZltVWNECD5yK+40+OCONzGw4OtmSdTpVi8/KFgo9dqM= go.unistack.org/micro-proto/v3 v3.2.5/go.mod h1:ZltVWNECD5yK+40+OCONzGw4OtmSdTpVi8/KFgo9dqM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=

View File

@ -22,13 +22,14 @@ import (
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
"sync"
"go.unistack.org/micro-proto/v3/api" "go.unistack.org/micro-proto/v3/api"
// v2 "go.unistack.org/micro-proto/v3/openapiv2"
v3 "go.unistack.org/micro-proto/v3/openapiv3" v3 "go.unistack.org/micro-proto/v3/openapiv3"
"google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
) )
const ( const (
@ -47,6 +48,19 @@ type openapiv3Generator struct {
namedPathPattern *regexp.Regexp namedPathPattern *regexp.Regexp
} }
var (
once sync.Once
protofiles = &protoregistry.Files{}
)
func protofilesAdd(plugin *protogen.Plugin) {
for path, f := range plugin.FilesByPath {
if _, err := protofiles.FindFileByPath(path); err != nil {
protofiles.RegisterFile(f.Desc)
}
}
}
// openapiv3Generate creates a new generator for a protoc plugin invocation. // openapiv3Generate creates a new generator for a protoc plugin invocation.
func (g *Generator) openapiv3Generate(component string, plugin *protogen.Plugin) error { func (g *Generator) openapiv3Generate(component string, plugin *protogen.Plugin) error {
og := &openapiv3Generator{ og := &openapiv3Generator{
@ -61,6 +75,8 @@ func (g *Generator) openapiv3Generate(component string, plugin *protogen.Plugin)
namedPathPattern: regexp.MustCompile("{(.+)=(.+)}"), namedPathPattern: regexp.MustCompile("{(.+)=(.+)}"),
} }
protofilesAdd(plugin)
d := og.buildDocumentV3(plugin) d := og.buildDocumentV3(plugin)
bytes, err := d.YAMLValue("Generated with protoc-gen-go-micro\n") bytes, err := d.YAMLValue("Generated with protoc-gen-go-micro\n")
if err != nil { if err != nil {
@ -245,14 +261,6 @@ func (g *openapiv3Generator) addPathsToDocumentV3(d *v3.Document, file *protogen
outputMessage := method.Output outputMessage := method.Output
operationID := service.GoName + "_" + method.GoName operationID := service.GoName + "_" + method.GoName
/*
e2opt := proto.GetExtension(method.Desc.Options(), v2.E_Openapiv2Operation)
if e2opt != nil && e2opt != v2.E_Openapiv2Operation.InterfaceOf(v2.E_Openapiv2Operation.Zero()) {
if opt, ok := e2opt.(*v2.Operation); ok && opt.OperationId != "" {
operationID = opt.OperationId
}
}
*/
e3opt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) e3opt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation)
if e3opt != nil && e3opt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { if e3opt != nil && e3opt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) {
if opt, ok := e3opt.(*v3.Operation); ok && opt.OperationId != "" { if opt, ok := e3opt.(*v3.Operation); ok && opt.OperationId != "" {
@ -640,22 +648,71 @@ func (g *openapiv3Generator) buildOperationV3(
} }
} }
// Create the response. var responses *v3.Responses
responses := &v3.Responses{ if eopt != nil && eopt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) {
ResponseOrReference: []*v3.NamedResponseOrReference{ opt := eopt.(*v3.Operation)
{ if r := opt.Responses; r != nil {
Name: "200", responses = r
Value: &v3.ResponseOrReference{ }
Oneof: &v3.ResponseOrReference_Response{
Response: &v3.Response{ if ref := responses.Default.GetReference(); ref != nil && ref.GetXRef() != "" {
Description: "OK", xref := strings.TrimPrefix(ref.GetXRef(), ".")
Content: g.responseContentForMessage(outputMessage), description := "Default"
}, if strings.Contains(xref, "micro.errors.Error") {
description += " Error"
}
desc, err := protofiles.FindDescriptorByName(protoreflect.FullName(xref))
if err != nil {
log.Printf("unknown ref type %s err %v", xref, err)
} else {
responses.Default.Oneof = &v3.ResponseOrReference_Response{
Response: &v3.Response{
Description: description,
Content: g.responseContentForMessage(&protogen.Message{
Desc: desc.(protoreflect.MessageDescriptor),
}),
}, },
}
}
}
for _, rref := range responses.GetResponseOrReference() {
if ref := rref.Value.GetReference(); ref != nil && ref.GetXRef() != "" {
xref := strings.TrimPrefix(ref.GetXRef(), ".")
description := "Default"
if strings.Contains(xref, "micro.errors.Error") {
description += " Error"
}
desc, err := protofiles.FindDescriptorByName(protoreflect.FullName(xref))
if err != nil {
log.Printf("unknown ref type %s err %v", xref, err)
} else {
responses.Default.Oneof = &v3.ResponseOrReference_Response{
Response: &v3.Response{
Description: description,
Content: g.responseContentForMessage(&protogen.Message{
Desc: desc.(protoreflect.MessageDescriptor),
}),
},
}
}
}
}
} else {
responses = &v3.Responses{}
}
// Create the response.
responses.ResponseOrReference = append(responses.ResponseOrReference, &v3.NamedResponseOrReference{
Name: "200",
Value: &v3.ResponseOrReference{
Oneof: &v3.ResponseOrReference_Response{
Response: &v3.Response{
Description: "OK",
Content: g.responseContentForMessage(outputMessage),
}, },
}, },
}, },
} })
// Create the operation. // Create the operation.
op := &v3.Operation{ op := &v3.Operation{
@ -682,7 +739,6 @@ func (g *openapiv3Generator) buildOperationV3(
// Pass the entire request message as the request body. // Pass the entire request message as the request body.
typeName := g.fullMessageTypeName(inputMessage.Desc) typeName := g.fullMessageTypeName(inputMessage.Desc)
requestSchema = g.schemaOrReferenceForType(typeName) requestSchema = g.schemaOrReferenceForType(typeName)
} else { } else {
// If body refers to a message field, use that type. // If body refers to a message field, use that type.
for _, field := range inputMessage.Fields { for _, field := range inputMessage.Fields {

View File

@ -16,8 +16,8 @@ var (
microServerPackage = protogen.GoImportPath("go.unistack.org/micro/v3/server") microServerPackage = protogen.GoImportPath("go.unistack.org/micro/v3/server")
microClientHttpPackage = protogen.GoImportPath("go.unistack.org/micro-client-http/v3") microClientHttpPackage = protogen.GoImportPath("go.unistack.org/micro-client-http/v3")
microServerHttpPackage = protogen.GoImportPath("go.unistack.org/micro-server-http/v3") microServerHttpPackage = protogen.GoImportPath("go.unistack.org/micro-server-http/v3")
microCodecPackage = protogen.GoImportPath("go.unistack.org/micro/v3/codec") microCodecPackage = protogen.GoImportPath("go.unistack.org/micro-proto/v3/codec")
microErrorsPackage = protogen.GoImportPath("go.unistack.org/micro/v3/errors") microErrorsPackage = protogen.GoImportPath("go.unistack.org/micro-proto/v3/errors")
timePackage = protogen.GoImportPath("time") timePackage = protogen.GoImportPath("time")
deprecationComment = "// Deprecated: Do not use." deprecationComment = "// Deprecated: Do not use."
versionComment = "v3.5.3" versionComment = "v3.5.3"