From a974da658bffa33e59c3ae611f8f7fe2936fe2ce Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Tue, 23 Feb 2021 14:30:23 +0300 Subject: [PATCH] generate error types for http Signed-off-by: Vasiliy Tolstov --- gorilla.go | 3 +- http.go | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- main.go | 2 -- micro.go | 3 +- openapi.go | 39 ------------------------ rpc.go | 3 +- util.go | 2 +- 7 files changed, 93 insertions(+), 48 deletions(-) delete mode 100644 openapi.go diff --git a/gorilla.go b/gorilla.go index 7a6db0a..ec1921b 100644 --- a/gorilla.go +++ b/gorilla.go @@ -34,8 +34,9 @@ func (g *Generator) gorillaGenerate(component string, plugin *protogen.Plugin) e gfile.P(`"net/http"`) gfile.P(`"reflect"`) gfile.P(`"strings"`) - gfile.P(`mux "github.com/gorilla/mux"`) + gfile.P() gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) + gfile.P(`mux "github.com/gorilla/mux"`) gfile.P(")") gfile.P() diff --git a/http.go b/http.go index f32bc06..446d817 100644 --- a/http.go +++ b/http.go @@ -1,10 +1,21 @@ package main import ( + "strings" + + openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" "google.golang.org/protobuf/compiler/protogen" + "google.golang.org/protobuf/proto" ) +type Error struct { + packageName string + types []string +} + func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) error { + errors := make(map[string]struct{}) + for _, file := range plugin.Files { if !file.Generate { continue @@ -13,7 +24,7 @@ func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) erro continue } - gname := file.GeneratedFilenamePrefix + "_" + component + ".pb.go" + gname := file.GeneratedFilenamePrefix + "_micro_" + component + ".pb.go" gfile := plugin.NewGeneratedFile(gname, ".") gfile.P("// Code generated by protoc-gen-micro") @@ -23,10 +34,11 @@ func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) erro gfile.P() gfile.P("import (") gfile.P(`"context"`) + gfile.P() gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) + gfile.P(`micro_client_http "github.com/unistack-org/micro-client-http/v3"`) gfile.P(`micro_client "github.com/unistack-org/micro/v3/client"`) gfile.P(`micro_server "github.com/unistack-org/micro/v3/server"`) - gfile.P(`micro_client_http "github.com/unistack-org/micro-client-http/v3"`) gfile.P(")") gfile.P() @@ -45,8 +57,81 @@ func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) erro generateServiceServer(gfile, service) generateServiceServerMethods(gfile, service) generateServiceRegister(gfile, service) + if component == "http" { + for k, v := range getErrors(service) { + errors[k] = v + } + } } } + files := make(map[string]*Error) + for _, file := range plugin.Files { + if !file.Generate { + continue + } + + err, ok := files[file.GeneratedFilenamePrefix] + if !ok { + err = &Error{packageName: string(file.GoPackageName)} + } + fok := false + for _, message := range file.Messages { + if _, ok := errors["."+string(message.Desc.FullName())]; ok { + fok = true + err.types = append(err.types, string(message.Desc.FullName())) + } + } + if fok { + files[file.GeneratedFilenamePrefix] = err + } + } + + for file, err := range files { + gfile := plugin.NewGeneratedFile(file+"_micro_errors.pb.go", ".") + generateServiceErrors(gfile, err) + } + return nil } + +func getErrors(service *protogen.Service) map[string]struct{} { + errors := make(map[string]struct{}) + + for _, method := range service.Methods { + if method.Desc.Options() == nil { + continue + } + if !proto.HasExtension(method.Desc.Options(), openapi_options.E_Openapiv2Operation) { + continue + } + + opts := proto.GetExtension(method.Desc.Options(), openapi_options.E_Openapiv2Operation) + if opts == nil { + continue + } + + r := opts.(*openapi_options.Operation) + for _, response := range r.Responses { + if response.Schema == nil || response.Schema.JsonSchema == nil { + continue + } + errors[response.Schema.JsonSchema.Ref] = struct{}{} + } + } + + return errors +} + +func generateServiceErrors(gfile *protogen.GeneratedFile, err *Error) { + gfile.P("package ", err.packageName) + gfile.P("import (") + gfile.P(`"fmt"`) + gfile.P(")") + for _, typ := range err.types { + gfile.P("func (err *", typ[strings.LastIndex(typ, ".")+1:], ") Error() string {") + gfile.P(`return fmt.Sprintf("%#v", err)`) + gfile.P("}") + gfile.P() + } +} diff --git a/main.go b/main.go index b421504..a44be67 100644 --- a/main.go +++ b/main.go @@ -48,8 +48,6 @@ func (g *Generator) Generate(plugin *protogen.Plugin) error { err = g.httpGenerate(component, plugin) case "grpc", "rpc": err = g.rpcGenerate(component, plugin) - case "openapi", "swagger": - err = g.openapiGenerate(component, plugin) case "gorilla": err = g.gorillaGenerate(component, plugin) case "chi": diff --git a/micro.go b/micro.go index 027cbef..8ed1be9 100644 --- a/micro.go +++ b/micro.go @@ -23,9 +23,9 @@ func (g *Generator) microGenerate(component string, plugin *protogen.Plugin) err gfile.P() gfile.P("import (") gfile.P(`"context"`) + gfile.P() gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) gfile.P(`micro_client "github.com/unistack-org/micro/v3/client"`) - gfile.P(`micro_server "github.com/unistack-org/micro/v3/server"`) gfile.P(")") gfile.P() @@ -34,7 +34,6 @@ func (g *Generator) microGenerate(component string, plugin *protogen.Plugin) err gfile.P("_ ", "micro_api.Endpoint") gfile.P("_ ", "context.Context") gfile.P(" _ ", "micro_client.Option") - gfile.P(" _ ", "micro_server.Option") gfile.P(")") gfile.P() diff --git a/openapi.go b/openapi.go deleted file mode 100644 index 07f5a29..0000000 --- a/openapi.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - - "google.golang.org/protobuf/compiler/protogen" -) - -func (g *Generator) openapiGenerate(component string, plugin *protogen.Plugin) error { - for _, file := range plugin.Files { - - if !file.Generate { - continue - } - - // 1. Initialise a buffer to hold the generated code - var buf bytes.Buffer - - // 2. Write the package name - pkg := fmt.Sprintf("package %s", file.GoPackageName) - buf.Write([]byte(pkg)) - - // 3. For each message add our Foo() method - for _, msg := range file.Proto.MessageType { - buf.Write([]byte(fmt.Sprintf(`func (x %s) Foo() string { -return "bar"}`, *msg.Name))) - } - - // 4. Specify the output filename, in this case test.foo.go - filename := file.GeneratedFilenamePrefix + ".foo.go" - file := plugin.NewGeneratedFile(filename, ".") - - // 5. Pass the data from our buffer to the plugin file struct - file.Write(buf.Bytes()) - } - - return nil -} diff --git a/rpc.go b/rpc.go index 6471620..48035ec 100644 --- a/rpc.go +++ b/rpc.go @@ -13,7 +13,7 @@ func (g *Generator) rpcGenerate(component string, plugin *protogen.Plugin) error continue } - gname := file.GeneratedFilenamePrefix + "_" + component + ".pb.go" + gname := file.GeneratedFilenamePrefix + "_micro_" + component + ".pb.go" gfile := plugin.NewGeneratedFile(gname, ".") gfile.P("// Code generated by protoc-gen-micro") @@ -23,6 +23,7 @@ func (g *Generator) rpcGenerate(component string, plugin *protogen.Plugin) error gfile.P() gfile.P("import (") gfile.P(`"context"`) + gfile.P() gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) gfile.P(`micro_client "github.com/unistack-org/micro/v3/client"`) gfile.P(`micro_server "github.com/unistack-org/micro/v3/server"`) diff --git a/util.go b/util.go index 4b6fcda..9d2d06e 100644 --- a/util.go +++ b/util.go @@ -360,7 +360,7 @@ func generateServiceServerStreamInterface(gfile *protogen.GeneratedFile, service func generateServiceEndpoints(gfile *protogen.GeneratedFile, service *protogen.Service) { serviceName := strings.TrimSuffix(service.GoName, "Service") - gfile.P("//New", serviceName, "Endpoints provides api endpoints metdata for ", serviceName, " service") + gfile.P("// New", serviceName, "Endpoints provides api endpoints metdata for ", serviceName, " service") gfile.P("func New", serviceName, "Endpoints() []*micro_api.Endpoint {") gfile.P("return []*", "micro_api.Endpoint{") for _, method := range service.Methods {