Skip to content

Commit 7850693

Browse files
Forrestkevwan
authored andcommitted
feat(goctl): add filename annotation to group related API routes for generating api service code
1 parent 94e2f5b commit 7850693

File tree

8 files changed

+446
-118
lines changed

8 files changed

+446
-118
lines changed

tools/goctl/api/gogen/genhandlers.go

Lines changed: 110 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -23,61 +23,125 @@ var (
2323
sseHandlerTemplate string
2424
)
2525

26-
func genHandler(dir, rootPkg, projectPkg string, cfg *config.Config, group spec.Group, route spec.Route) error {
27-
handler := getHandlerName(route)
28-
handlerPath := getHandlerFolderPath(group, route)
29-
pkgName := handlerPath[strings.LastIndex(handlerPath, "/")+1:]
30-
logicName := defaultLogicPackage
31-
if handlerPath != handlerDir {
32-
handler = strings.Title(handler)
33-
logicName = pkgName
34-
}
35-
filename, err := format.FileNamingFormat(cfg.NamingFormat, handler)
36-
if err != nil {
37-
return err
26+
func genHandlers(dir, rootPkg, projectPkg string, cfg *config.Config, api *spec.ApiSpec) error {
27+
type fileKey struct {
28+
subdir string
29+
filename string
3830
}
3931

40-
var builtinTemplate = handlerTemplate
41-
var templateFile = handlerTemplateFile
42-
sse := group.GetAnnotation("sse")
43-
if sse == "true" {
44-
builtinTemplate = sseHandlerTemplate
45-
templateFile = sseHandlerTemplateFile
32+
type handlerFile struct {
33+
pkgName string
34+
imports []string
35+
handlers []map[string]any
36+
sseEnable bool
4637
}
4738

48-
return genFile(fileGenConfig{
49-
dir: dir,
50-
subdir: getHandlerFolderPath(group, route),
51-
filename: filename + ".go",
52-
templateName: "handlerTemplate",
53-
category: category,
54-
templateFile: templateFile,
55-
builtinTemplate: builtinTemplate,
56-
data: map[string]any{
57-
"PkgName": pkgName,
58-
"ImportPackages": genHandlerImports(group, route, rootPkg),
59-
"HandlerName": handler,
60-
"RequestType": util.Title(route.RequestTypeName()),
61-
"ResponseType": responseGoTypeName(route, typesPacket),
62-
"LogicName": logicName,
63-
"LogicType": strings.Title(getLogicName(route)),
64-
"Call": strings.Title(strings.TrimSuffix(handler, "Handler")),
65-
"HasResp": len(route.ResponseTypeName()) > 0,
66-
"HasRequest": len(route.RequestTypeName()) > 0,
67-
"HasDoc": len(route.JoinedDoc()) > 0,
68-
"Doc": getDoc(route.JoinedDoc()),
69-
"projectPkg": projectPkg,
70-
"version": version.BuildVersion,
71-
},
72-
})
73-
}
39+
files := make(map[fileKey]*handlerFile)
7440

75-
func genHandlers(dir, rootPkg, projectPkg string, cfg *config.Config, api *spec.ApiSpec) error {
7641
for _, group := range api.Service.Groups {
42+
sse := group.GetAnnotation("sse") == "true"
7743
for _, route := range group.Routes {
78-
if err := genHandler(dir, rootPkg, projectPkg, cfg, group, route); err != nil {
44+
handlerName := getHandlerName(route)
45+
handlerPath := getHandlerFolderPath(group, route)
46+
pkgName := handlerPath[strings.LastIndex(handlerPath, "/")+1:]
47+
logicName := defaultLogicPackage
48+
if handlerPath != handlerDir {
49+
handlerName = strings.Title(handlerName)
50+
logicName = pkgName
51+
}
52+
53+
fileBase := route.GetAnnotation(filenameProperty)
54+
if len(fileBase) == 0 {
55+
fileBase = group.GetAnnotation(filenameProperty)
56+
}
57+
if len(fileBase) == 0 {
58+
fileBase = handlerName
59+
}
60+
61+
fileBase, err := format.FileNamingFormat(cfg.NamingFormat, fileBase)
62+
if err != nil {
7963
return err
8064
}
65+
66+
subdir := getHandlerFolderPath(group, route)
67+
key := fileKey{
68+
subdir: subdir,
69+
filename: fileBase + ".go",
70+
}
71+
72+
f, ok := files[key]
73+
if !ok {
74+
f = &handlerFile{
75+
pkgName: pkgName,
76+
imports: nil,
77+
handlers: nil,
78+
sseEnable: sse,
79+
}
80+
files[key] = f
81+
}
82+
83+
importsStr := genHandlerImports(group, route, rootPkg)
84+
for _, imp := range strings.Split(importsStr, "\n\t") {
85+
imp = strings.TrimSpace(imp)
86+
if len(imp) == 0 {
87+
continue
88+
}
89+
found := false
90+
for _, existing := range f.imports {
91+
if existing == imp {
92+
found = true
93+
break
94+
}
95+
}
96+
if !found {
97+
f.imports = append(f.imports, imp)
98+
}
99+
}
100+
101+
handlerData := map[string]any{
102+
"HandlerName": handlerName,
103+
"RequestType": util.Title(route.RequestTypeName()),
104+
"ResponseType": responseGoTypeName(route, typesPacket),
105+
"LogicName": logicName,
106+
"LogicType": strings.Title(getLogicName(route)),
107+
"Call": strings.Title(strings.TrimSuffix(handlerName, "Handler")),
108+
"HasResp": len(route.ResponseTypeName()) > 0,
109+
"HasRequest": len(route.RequestTypeName()) > 0,
110+
"HasDoc": len(route.JoinedDoc()) > 0,
111+
"Doc": getDoc(route.JoinedDoc()),
112+
}
113+
114+
f.handlers = append(f.handlers, handlerData)
115+
}
116+
}
117+
118+
for key, f := range files {
119+
importsJoined := strings.Join(f.imports, "\n\t")
120+
121+
builtinTemplate := handlerTemplate
122+
templateFile := handlerTemplateFile
123+
if f.sseEnable {
124+
builtinTemplate = sseHandlerTemplate
125+
templateFile = sseHandlerTemplateFile
126+
}
127+
128+
if err := genFile(fileGenConfig{
129+
dir: dir,
130+
subdir: key.subdir,
131+
filename: key.filename,
132+
templateName: "handlerTemplate",
133+
category: category,
134+
templateFile: templateFile,
135+
builtinTemplate: builtinTemplate,
136+
data: map[string]any{
137+
"PkgName": f.pkgName,
138+
"ImportPackages": importsJoined,
139+
"Handlers": f.handlers,
140+
"projectPkg": projectPkg,
141+
"version": version.BuildVersion,
142+
},
143+
}); err != nil {
144+
return err
81145
}
82146
}
83147

tools/goctl/api/gogen/genlogic.go

Lines changed: 127 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -25,79 +25,144 @@ var (
2525
)
2626

2727
func genLogic(dir, rootPkg, projectPkg string, cfg *config.Config, api *spec.ApiSpec) error {
28-
for _, g := range api.Service.Groups {
29-
for _, r := range g.Routes {
30-
err := genLogicByRoute(dir, rootPkg, projectPkg, cfg, g, r)
28+
type fileKey struct {
29+
subdir string
30+
filename string
31+
}
32+
33+
type logicFile struct {
34+
pkgName string
35+
imports []string
36+
logics []map[string]any
37+
sseEnable bool
38+
}
39+
40+
files := make(map[fileKey]*logicFile)
41+
42+
for _, group := range api.Service.Groups {
43+
sse := group.GetAnnotation("sse") == "true"
44+
for _, route := range group.Routes {
45+
logic := getLogicName(route)
46+
47+
fileBase := route.GetAnnotation(filenameProperty)
48+
if len(fileBase) == 0 {
49+
fileBase = group.GetAnnotation(filenameProperty)
50+
}
51+
if len(fileBase) == 0 {
52+
fileBase = logic
53+
}
54+
55+
goFile, err := format.FileNamingFormat(cfg.NamingFormat, fileBase)
3156
if err != nil {
3257
return err
3358
}
59+
60+
subDir := getLogicFolderPath(group, route)
61+
key := fileKey{
62+
subdir: subDir,
63+
filename: goFile + ".go",
64+
}
65+
66+
f, ok := files[key]
67+
if !ok {
68+
f = &logicFile{
69+
pkgName: subDir[strings.LastIndex(subDir, "/")+1:],
70+
imports: nil,
71+
logics: nil,
72+
sseEnable: sse,
73+
}
74+
files[key] = f
75+
}
76+
77+
imports := genLogicImports(route, rootPkg)
78+
for _, imp := range strings.Split(imports, "\n\t") {
79+
imp = strings.TrimSpace(imp)
80+
if len(imp) == 0 {
81+
continue
82+
}
83+
found := false
84+
for _, existing := range f.imports {
85+
if existing == imp {
86+
found = true
87+
break
88+
}
89+
}
90+
if !found {
91+
f.imports = append(f.imports, imp)
92+
}
93+
}
94+
95+
var responseString string
96+
var returnString string
97+
var requestString string
98+
if len(route.ResponseTypeName()) > 0 {
99+
resp := responseGoTypeName(route, typesPacket)
100+
responseString = "(resp " + resp + ", err error)"
101+
returnString = "return"
102+
} else {
103+
responseString = "error"
104+
returnString = "return nil"
105+
}
106+
if len(route.RequestTypeName()) > 0 {
107+
requestString = "req *" + requestGoTypeName(route, typesPacket)
108+
}
109+
110+
if sse {
111+
responseString = "error"
112+
returnString = "return nil"
113+
resp := responseGoTypeName(route, typesPacket)
114+
if len(requestString) == 0 {
115+
requestString = "client chan<- " + resp
116+
} else {
117+
requestString += ", client chan<- " + resp
118+
}
119+
}
120+
121+
logicData := map[string]any{
122+
"logic": strings.Title(logic),
123+
"function": strings.Title(strings.TrimSuffix(logic, "Logic")),
124+
"responseType": responseString,
125+
"returnString": returnString,
126+
"request": requestString,
127+
"hasDoc": len(route.JoinedDoc()) > 0,
128+
"doc": getDoc(route.JoinedDoc()),
129+
}
130+
131+
f.logics = append(f.logics, logicData)
34132
}
35133
}
36-
return nil
37-
}
38134

39-
func genLogicByRoute(dir, rootPkg, projectPkg string, cfg *config.Config, group spec.Group, route spec.Route) error {
40-
logic := getLogicName(route)
41-
goFile, err := format.FileNamingFormat(cfg.NamingFormat, logic)
42-
if err != nil {
43-
return err
44-
}
135+
for key, f := range files {
136+
importsJoined := strings.Join(f.imports, "\n\t")
45137

46-
imports := genLogicImports(route, rootPkg)
47-
var responseString string
48-
var returnString string
49-
var requestString string
50-
if len(route.ResponseTypeName()) > 0 {
51-
resp := responseGoTypeName(route, typesPacket)
52-
responseString = "(resp " + resp + ", err error)"
53-
returnString = "return"
54-
} else {
55-
responseString = "error"
56-
returnString = "return nil"
57-
}
58-
if len(route.RequestTypeName()) > 0 {
59-
requestString = "req *" + requestGoTypeName(route, typesPacket)
60-
}
138+
builtinTemplate := logicTemplate
139+
templateFile := logicTemplateFile
140+
if f.sseEnable {
141+
builtinTemplate = sseLogicTemplate
142+
templateFile = sseLogicTemplateFile
143+
}
61144

62-
subDir := getLogicFolderPath(group, route)
63-
builtinTemplate := logicTemplate
64-
templateFile := logicTemplateFile
65-
sse := group.GetAnnotation("sse")
66-
if sse == "true" {
67-
builtinTemplate = sseLogicTemplate
68-
templateFile = sseLogicTemplateFile
69-
responseString = "error"
70-
returnString = "return nil"
71-
resp := responseGoTypeName(route, typesPacket)
72-
if len(requestString) == 0 {
73-
requestString = "client chan<- " + resp
74-
} else {
75-
requestString += ", client chan<- " + resp
145+
if err := genFile(fileGenConfig{
146+
dir: dir,
147+
subdir: key.subdir,
148+
filename: key.filename,
149+
templateName: "logicTemplate",
150+
category: category,
151+
templateFile: templateFile,
152+
builtinTemplate: builtinTemplate,
153+
data: map[string]any{
154+
"pkgName": f.pkgName,
155+
"imports": importsJoined,
156+
"Logics": f.logics,
157+
"projectPkg": projectPkg,
158+
"version": version.BuildVersion,
159+
},
160+
}); err != nil {
161+
return err
76162
}
77163
}
78164

79-
return genFile(fileGenConfig{
80-
dir: dir,
81-
subdir: subDir,
82-
filename: goFile + ".go",
83-
templateName: "logicTemplate",
84-
category: category,
85-
templateFile: templateFile,
86-
builtinTemplate: builtinTemplate,
87-
data: map[string]any{
88-
"pkgName": subDir[strings.LastIndex(subDir, "/")+1:],
89-
"imports": imports,
90-
"logic": strings.Title(logic),
91-
"function": strings.Title(strings.TrimSuffix(logic, "Logic")),
92-
"responseType": responseString,
93-
"returnString": returnString,
94-
"request": requestString,
95-
"hasDoc": len(route.JoinedDoc()) > 0,
96-
"doc": getDoc(route.JoinedDoc()),
97-
"projectPkg": projectPkg,
98-
"version": version.BuildVersion,
99-
},
100-
})
165+
return nil
101166
}
102167

103168
func getLogicFolderPath(group spec.Group, route spec.Route) string {

tools/goctl/api/gogen/handler.tpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
{{.ImportPackages}}
1111
)
1212

13+
{{range .Handlers}}
1314
{{if .HasDoc}}{{.Doc}}{{end}}
1415
func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
1516
return func(w http.ResponseWriter, r *http.Request) {
@@ -28,3 +29,4 @@ func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
2829
}
2930
}
3031
}
32+
{{end}}

0 commit comments

Comments
 (0)