diff --git a/openapiv3.go b/openapiv3.go index 4c1f255..f5e5e7c 100644 --- a/openapiv3.go +++ b/openapiv3.go @@ -24,6 +24,7 @@ import ( "strings" "go.unistack.org/micro-proto/v3/api" + v2 "go.unistack.org/micro-proto/v3/openapiv2" v3 "go.unistack.org/micro-proto/v3/openapiv3" "google.golang.org/protobuf/compiler/protogen" jsonpb "google.golang.org/protobuf/encoding/protojson" @@ -243,9 +244,15 @@ func (g *openapiv3Generator) addPathsToDocumentV3(d *v3.Document, file *protogen outputMessage := method.Output operationID := service.GoName + "_" + method.GoName - eopt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) - if eopt != nil && eopt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { - if opt, ok := eopt.(*v3.Operation); ok && opt.OperationId != "" { + 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) + if e3opt != nil && e3opt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { + if opt, ok := e3opt.(*v3.Operation); ok && opt.OperationId != "" { operationID = opt.OperationId } } @@ -342,7 +349,7 @@ func (g *openapiv3Generator) formatMessageName(message *protogen.Message) string } func (g *openapiv3Generator) formatFieldName(field *protogen.Field) string { - log.Printf("proto %s json %s", string(field.Desc.Name()), field.Desc.JSONName()) + // log.Printf("proto %s json %s", string(field.Desc.Name()), field.Desc.JSONName()) if g.naming == "proto" { return string(field.Desc.Name()) } @@ -417,7 +424,7 @@ func (g *openapiv3Generator) _buildQueryParamsV3(field *protogen.Field, depths m }) return parameters } - log.Printf("DDDD %#+v", field.Message) + // Sub messages are allowed, even circular, as long as the final type is a primitive. // Go through each of the sub message fields for _, subField := range field.Message.Fields { @@ -591,14 +598,14 @@ func (g *openapiv3Generator) buildOperationV3( if bodyField != "*" { for _, field := range inputMessage.Fields { fieldName := string(field.Desc.Name()) - log.Printf("bodyfield %v coveredParameters %#+v fieldName %v", bodyField, coveredParameters, fieldName) + // log.Printf("bodyfield %v coveredParameters %#+v fieldName %v", bodyField, coveredParameters, fieldName) if !contains(coveredParameters, fieldName) && fieldName != bodyField { - log.Printf("append!!! field %#+v", field) + // log.Printf("append!!! field %#+v", field) fieldParams := g.buildQueryParamsV3(field) - log.Printf("add param %#+v field %#+v", fieldParams, field) + // log.Printf("add param %#+v field %#+v", fieldParams, field) parameters = append(parameters, fieldParams...) } else { - log.Printf("not append") + // log.Printf("not append") } } } diff --git a/util.go b/util.go index 9443274..5c771b7 100644 --- a/util.go +++ b/util.go @@ -80,6 +80,35 @@ func generateServiceClientMethods(gfile *protogen.GeneratedFile, service *protog gfile.P(microClientHttpPackage.Ident("ErrorMap"), "(errmap),") gfile.P(")") } + if proto.HasExtension(method.Desc.Options(), v3.E_Openapiv3Operation) { + opts := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) + if opts != nil { + r := opts.(*v3.Operation) + gfile.P("errmap := make(map[string]interface{}, ", len(r.Responses.ResponseOrReference), ")") + for _, rsp := range r.Responses.ResponseOrReference { + if schema := rsp.Value.GetReference(); schema != nil { + ref := schema.XRef + if strings.HasPrefix(ref, "."+string(service.Desc.ParentFile().Package())+".") { + ref = strings.TrimPrefix(ref, "."+string(service.Desc.ParentFile().Package())+".") + } + if ref[0] == '.' { + ref = ref[1:] + } + switch ref { + case "micro.codec.Frame": + gfile.P(`errmap["`, rsp.Name, `"] = &`, microCodecPackage.Ident("Frame"), "{}") + case "micro.errors.Error": + gfile.P(`errmap["`, rsp.Name, `"] = &`, microErrorsPackage.Ident("Error"), "{}") + default: + gfile.P(`errmap["`, rsp.Name, `"] = &`, ref, "{}") + } + } + } + } + gfile.P("opts = append(opts,") + gfile.P(microClientHttpPackage.Ident("ErrorMap"), "(errmap),") + gfile.P(")") + } if proto.HasExtension(method.Desc.Options(), api_options.E_Http) { gfile.P("opts = append(opts,") @@ -99,10 +128,36 @@ func generateServiceClientMethods(gfile *protogen.GeneratedFile, service *protog parameters := make(map[string]map[string]string) // Build a list of header parameters. - eopt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) - if eopt != nil && eopt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { - opt := eopt.(*v3.Operation) + e2opt := proto.GetExtension(method.Desc.Options(), v2.E_Openapiv2Operation) + if e2opt != nil && e2opt != v2.E_Openapiv2Operation.InterfaceOf(v2.E_Openapiv2Operation.Zero()) { + opt := e2opt.(*v2.Operation) for _, paramOrRef := range opt.Parameters { + parameter := paramOrRef.GetParameter() + // NonBodyParameter() + if parameter == nil { + continue + } + nonBodyParameter := parameter.GetNonBodyParameter() + if nonBodyParameter == nil { + continue + } + headerParameter := nonBodyParameter.GetHeaderParameterSubSchema() + if headerParameter.In != "header" && headerParameter.In != "cookie" { + continue + } + in, ok := parameters[headerParameter.In] + if !ok { + in = make(map[string]string) + parameters[headerParameter.In] = in + } + in[headerParameter.Name] = fmt.Sprintf("%v", headerParameter.Required) + } + } + e3opt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) + if e3opt != nil && e3opt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { + opt := e3opt.(*v3.Operation) + for _, paramOrRef := range opt.Parameters { + parameter := paramOrRef.GetParameter() if parameter == nil { continue @@ -258,9 +313,34 @@ func generateServiceServerMethods(gfile *protogen.GeneratedFile, service *protog } else { parameters := make(map[string]map[string]string) // Build a list of header parameters. - eopt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) - if eopt != nil && eopt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { - opt := eopt.(*v3.Operation) + e2opt := proto.GetExtension(method.Desc.Options(), v2.E_Openapiv2Operation) + if e2opt != nil && e2opt != v2.E_Openapiv2Operation.InterfaceOf(v2.E_Openapiv2Operation.Zero()) { + opt := e2opt.(*v2.Operation) + for _, paramOrRef := range opt.Parameters { + parameter := paramOrRef.GetParameter() + // NonBodyParameter() + if parameter == nil { + continue + } + nonBodyParameter := parameter.GetNonBodyParameter() + if nonBodyParameter == nil { + continue + } + headerParameter := nonBodyParameter.GetHeaderParameterSubSchema() + if headerParameter.In != "header" && headerParameter.In != "cookie" { + continue + } + in, ok := parameters[headerParameter.In] + if !ok { + in = make(map[string]string) + parameters[headerParameter.In] = in + } + in[headerParameter.Name] = fmt.Sprintf("%v", headerParameter.Required) + } + } + e3opt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) + if e3opt != nil && e3opt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { + opt := e3opt.(*v3.Operation) for _, paramOrRef := range opt.Parameters { parameter := paramOrRef.GetParameter() if parameter == nil {