generate error types for http

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2021-02-23 14:30:23 +03:00
parent e18a0f6942
commit a974da658b
7 changed files with 93 additions and 48 deletions

View File

@ -34,8 +34,9 @@ func (g *Generator) gorillaGenerate(component string, plugin *protogen.Plugin) e
gfile.P(`"net/http"`) gfile.P(`"net/http"`)
gfile.P(`"reflect"`) gfile.P(`"reflect"`)
gfile.P(`"strings"`) 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(`micro_api "github.com/unistack-org/micro/v3/api"`)
gfile.P(`mux "github.com/gorilla/mux"`)
gfile.P(")") gfile.P(")")
gfile.P() gfile.P()

89
http.go
View File

@ -1,10 +1,21 @@
package main package main
import ( 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/compiler/protogen"
"google.golang.org/protobuf/proto"
) )
type Error struct {
packageName string
types []string
}
func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) error { func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) error {
errors := make(map[string]struct{})
for _, file := range plugin.Files { for _, file := range plugin.Files {
if !file.Generate { if !file.Generate {
continue continue
@ -13,7 +24,7 @@ func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) erro
continue continue
} }
gname := file.GeneratedFilenamePrefix + "_" + component + ".pb.go" gname := file.GeneratedFilenamePrefix + "_micro_" + component + ".pb.go"
gfile := plugin.NewGeneratedFile(gname, ".") gfile := plugin.NewGeneratedFile(gname, ".")
gfile.P("// Code generated by protoc-gen-micro") 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()
gfile.P("import (") gfile.P("import (")
gfile.P(`"context"`) gfile.P(`"context"`)
gfile.P()
gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) 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_client "github.com/unistack-org/micro/v3/client"`)
gfile.P(`micro_server "github.com/unistack-org/micro/v3/server"`) 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(")")
gfile.P() gfile.P()
@ -45,8 +57,81 @@ func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) erro
generateServiceServer(gfile, service) generateServiceServer(gfile, service)
generateServiceServerMethods(gfile, service) generateServiceServerMethods(gfile, service)
generateServiceRegister(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 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()
}
}

View File

@ -48,8 +48,6 @@ func (g *Generator) Generate(plugin *protogen.Plugin) error {
err = g.httpGenerate(component, plugin) err = g.httpGenerate(component, plugin)
case "grpc", "rpc": case "grpc", "rpc":
err = g.rpcGenerate(component, plugin) err = g.rpcGenerate(component, plugin)
case "openapi", "swagger":
err = g.openapiGenerate(component, plugin)
case "gorilla": case "gorilla":
err = g.gorillaGenerate(component, plugin) err = g.gorillaGenerate(component, plugin)
case "chi": case "chi":

View File

@ -23,9 +23,9 @@ func (g *Generator) microGenerate(component string, plugin *protogen.Plugin) err
gfile.P() gfile.P()
gfile.P("import (") gfile.P("import (")
gfile.P(`"context"`) gfile.P(`"context"`)
gfile.P()
gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) 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_client "github.com/unistack-org/micro/v3/client"`)
gfile.P(`micro_server "github.com/unistack-org/micro/v3/server"`)
gfile.P(")") gfile.P(")")
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("_ ", "micro_api.Endpoint")
gfile.P("_ ", "context.Context") gfile.P("_ ", "context.Context")
gfile.P(" _ ", "micro_client.Option") gfile.P(" _ ", "micro_client.Option")
gfile.P(" _ ", "micro_server.Option")
gfile.P(")") gfile.P(")")
gfile.P() gfile.P()

View File

@ -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
}

3
rpc.go
View File

@ -13,7 +13,7 @@ func (g *Generator) rpcGenerate(component string, plugin *protogen.Plugin) error
continue continue
} }
gname := file.GeneratedFilenamePrefix + "_" + component + ".pb.go" gname := file.GeneratedFilenamePrefix + "_micro_" + component + ".pb.go"
gfile := plugin.NewGeneratedFile(gname, ".") gfile := plugin.NewGeneratedFile(gname, ".")
gfile.P("// Code generated by protoc-gen-micro") 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()
gfile.P("import (") gfile.P("import (")
gfile.P(`"context"`) gfile.P(`"context"`)
gfile.P()
gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) 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_client "github.com/unistack-org/micro/v3/client"`)
gfile.P(`micro_server "github.com/unistack-org/micro/v3/server"`) gfile.P(`micro_server "github.com/unistack-org/micro/v3/server"`)

View File

@ -360,7 +360,7 @@ func generateServiceServerStreamInterface(gfile *protogen.GeneratedFile, service
func generateServiceEndpoints(gfile *protogen.GeneratedFile, service *protogen.Service) { func generateServiceEndpoints(gfile *protogen.GeneratedFile, service *protogen.Service) {
serviceName := strings.TrimSuffix(service.GoName, "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("func New", serviceName, "Endpoints() []*micro_api.Endpoint {")
gfile.P("return []*", "micro_api.Endpoint{") gfile.P("return []*", "micro_api.Endpoint{")
for _, method := range service.Methods { for _, method := range service.Methods {