From 5756627904cc399137b1ebb83d032b26bf5facf6 Mon Sep 17 00:00:00 2001 From: fondoger Date: Thu, 16 Feb 2023 15:19:46 +0800 Subject: [PATCH] Fix Dart API generation bugs; Add ability to generate API for path parameters (#2887) * Fix bug in dartgen: Import path should match the generated api filename * Use Route.HandlerName as generated dart API function name Reasons: - There is bug when using url path name as function name, because it may have invalid characters such as ":" - Switching to HandlerName aligns with other languages such as typescript generation * [DartGen] Add ability to generate api for url path parameters such as /path/:param --- tools/goctl/api/dartgen/genapi.go | 10 +++-- tools/goctl/api/dartgen/util.go | 64 +++++++++++++++++++++++-------- tools/goctl/api/dartgen/vars.go | 17 ++++---- 3 files changed, 65 insertions(+), 26 deletions(-) diff --git a/tools/goctl/api/dartgen/genapi.go b/tools/goctl/api/dartgen/genapi.go index 7f735a81..aec5aa55 100644 --- a/tools/goctl/api/dartgen/genapi.go +++ b/tools/goctl/api/dartgen/genapi.go @@ -30,19 +30,21 @@ Future {{pathToFuncName .Path}}( {{if ne .Method "get"}}{{with .RequestType}}{{. {{end}}` const apiTemplateV2 = `import 'api.dart'; -import '../data/{{with .Info}}{{getBaseName .Title}}{{end}}.dart'; +import '../data/{{with .Service}}{{.Name}}{{end}}.dart'; {{with .Service}} /// {{.Name}} -{{range .Routes}} +{{range $i, $Route := .Routes}} /// --{{.Path}}-- /// /// request: {{with .RequestType}}{{.Name}}{{end}} /// response: {{with .ResponseType}}{{.Name}}{{end}} -Future {{pathToFuncName .Path}}( {{if ne .Method "get"}}{{with .RequestType}}{{.Name}} request,{{end}}{{end}} +Future {{normalizeHandlerName .Handler}}( + {{if hasUrlPathParams $Route}}{{extractPositionalParamsFromPath $Route}},{{end}} + {{if ne .Method "get"}}{{with .RequestType}}{{.Name}} request,{{end}}{{end}} {Function({{with .ResponseType}}{{.Name}}{{end}})? ok, Function(String)? fail, Function? eventually}) async { - await api{{if eq .Method "get"}}Get{{else}}Post{{end}}('{{.Path}}',{{if ne .Method "get"}}request,{{end}} + await api{{if eq .Method "get"}}Get{{else}}Post{{end}}({{makeDartRequestUrlPath $Route}},{{if ne .Method "get"}}request,{{end}} ok: (data) { if (ok != null) ok({{with .ResponseType}}{{.Name}}.fromJson(data){{end}}); }, fail: fail, eventually: eventually); diff --git a/tools/goctl/api/dartgen/util.go b/tools/goctl/api/dartgen/util.go index b6a52f15..907667c9 100644 --- a/tools/goctl/api/dartgen/util.go +++ b/tools/goctl/api/dartgen/util.go @@ -11,6 +11,18 @@ import ( "github.com/zeromicro/go-zero/tools/goctl/api/util" ) +const ( + formTagKey = "form" + pathTagKey = "path" + headerTagKey = "header" +) + +func normalizeHandlerName(handlerName string) string { + handler := strings.Replace(handlerName, "Handler", "", 1) + handler = lowCamelCase(handler) + return handler +} + func lowCamelCase(s string) string { if len(s) < 1 { return "" @@ -20,21 +32,6 @@ func lowCamelCase(s string) string { return util.ToLower(s[:1]) + s[1:] } -func pathToFuncName(path string) string { - if !strings.HasPrefix(path, "/") { - path = "/" + path - } - if !strings.HasPrefix(path, "/api") { - path = "/api" + path - } - - path = strings.Replace(path, "/", "_", -1) - path = strings.Replace(path, "-", "_", -1) - - camel := util.ToCamelCase(path) - return util.ToLower(camel[:1]) + camel[1:] -} - func getBaseName(str string) string { return path.Base(str) } @@ -170,3 +167,40 @@ func primitiveType(tp string) (string, bool) { return "", false } + +func hasUrlPathParams(route spec.Route) bool { + ds, ok := route.RequestType.(spec.DefineStruct) + if !ok { + return false + } + + return len(route.RequestTypeName()) > 0 && len(ds.GetTagMembers(pathTagKey)) > 0 +} + +func extractPositionalParamsFromPath(route spec.Route) string { + ds, ok := route.RequestType.(spec.DefineStruct) + if !ok { + return "" + } + + var params []string + for _, member := range ds.GetTagMembers(pathTagKey) { + params = append(params, fmt.Sprintf("%s %s", member.Type.Name(), getPropertyFromMember(member))) + } + + return strings.Join(params, ", ") +} + +func makeDartRequestUrlPath(route spec.Route) string { + path := route.Path + ds, ok := route.RequestType.(spec.DefineStruct) + if !ok { + return path + } + + for _, member := range ds.GetTagMembers(pathTagKey) { + path = strings.ReplaceAll(path, ":"+pathTagKey, "${"+getPropertyFromMember(member)+"}") + } + + return `"` + path + `"` +} diff --git a/tools/goctl/api/dartgen/vars.go b/tools/goctl/api/dartgen/vars.go index b1a98c6d..b34c3a6e 100644 --- a/tools/goctl/api/dartgen/vars.go +++ b/tools/goctl/api/dartgen/vars.go @@ -3,13 +3,16 @@ package dartgen import "text/template" var funcMap = template.FuncMap{ - "getBaseName": getBaseName, - "getPropertyFromMember": getPropertyFromMember, - "isDirectType": isDirectType, - "isClassListType": isClassListType, - "getCoreType": getCoreType, - "pathToFuncName": pathToFuncName, - "lowCamelCase": lowCamelCase, + "getBaseName": getBaseName, + "getPropertyFromMember": getPropertyFromMember, + "isDirectType": isDirectType, + "isClassListType": isClassListType, + "getCoreType": getCoreType, + "lowCamelCase": lowCamelCase, + "normalizeHandlerName": normalizeHandlerName, + "hasUrlPathParams": hasUrlPathParams, + "extractPositionalParamsFromPath": extractPositionalParamsFromPath, + "makeDartRequestUrlPath": makeDartRequestUrlPath, } const (