Skip to content

Commit ec16ee1

Browse files
committed
graphql done. wowzers
1 parent 74fd953 commit ec16ee1

11 files changed

Lines changed: 439 additions & 101 deletions

File tree

README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ go install github.com/andrearcaina/goforge@latest
3434

3535
### CLI Usage
3636

37-
This CLI can generate three server types, along with optional database scaffolding and configuration scripts. For now, it can generate a REST API and a gRPC server. See the [TODO](#todo) section for planned features.
37+
This CLI can generate three server types (REST, gRPC, GraphQL), along with optional database scaffolding and configuration (Makefile) scripts.
3838

3939
To generate a Go REST server, run:
4040

@@ -83,14 +83,12 @@ For example, running with all required flags will produce:
8383
Here is an example where you can trigger the TUI:\
8484
![goforge TUI](images/goforge-tui.png)
8585

86-
### TODO
86+
### Roadmap
8787

88-
In no particular order:
89-
90-
- [ ] Allow different server type boilerplates
88+
- [X] Allow different server type boilerplates
9189
- [x] REST (`go-chi`)
9290
- [x] gRPC (`grpc-go`)
93-
- [ ] GraphQL (`gqlgen`)
91+
- [X] GraphQL (`gqlgen`)
9492
- [x] Add Makefile support flag
9593
- [x] Add SQLc/database support flag
9694
- [x] Potentially add a docker-compose file to spin up a PostgreSQL instance

cmd/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ Cobra is a CLI library for Go that empowers applications.
1717
This application is a tool to generate the needed files
1818
to quickly create a Cobra application.`,
1919
Run: func(cmd *cobra.Command, args []string) {
20-
fmt.Println("v0.1.2")
20+
fmt.Println("v0.2.0")
2121
},
2222
}

internal/goforge/generator.go

Lines changed: 70 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,78 @@ import (
1212
)
1313

1414
func Generate(cfg *config.Config) error {
15-
// generate base files
1615
if err := generateBaseFiles(cfg); err != nil {
1716
return err
1817
}
1918

20-
// generate server files based on the selected server type
2119
switch cfg.Form.ServerTypeFlag {
2220
case config.REST:
23-
if err := generateRESTServer(cfg); err != nil {
21+
files := map[string]string{
22+
"rest/go.mod.tmpl": "go.mod",
23+
"rest/server.go.tmpl": "internal/api/server.go",
24+
"rest/handler.go.tmpl": "internal/api/handler.go",
25+
"rest/service.go.tmpl": "internal/api/service.go",
26+
}
27+
if err := generateRequiredFiles(cfg, files); err != nil {
2428
return err
2529
}
2630
case config.GRPC:
27-
if err := generateGRPCServer(cfg); err != nil {
31+
files := map[string]string{
32+
"grpc/go.mod.tmpl": "go.mod",
33+
"grpc/server.go.tmpl": "internal/api/server.go",
34+
"grpc/handler.go.tmpl": "internal/api/handler.go",
35+
"proto/user.proto.tmpl": "internal/pb/user/user.proto",
36+
}
37+
if err := generateRequiredFiles(cfg, files); err != nil {
38+
return err
39+
}
40+
case config.GraphQL:
41+
dirs := []string{
42+
"graph",
43+
"graph/generated",
44+
"graph/model",
45+
"graph/resolvers",
46+
"graph/schemas",
47+
}
48+
if err := generateDirs(cfg, dirs); err != nil {
49+
return err
50+
}
51+
52+
files := map[string]string{
53+
"graphql/go.mod.tmpl": "go.mod",
54+
"graphql/server.go.tmpl": "internal/api/server.go",
55+
"graphql/gqlgen.yml.tmpl": "gqlgen.yml",
56+
"graphql/schemas/user.graphqls.tmpl": "graph/schemas/user.graphqls",
57+
}
58+
if err := generateRequiredFiles(cfg, files); err != nil {
2859
return err
2960
}
3061
}
3162

32-
// generate database files if flag is set
3363
if cfg.Form.DatabaseFlag {
34-
if err := generateDBFiles(cfg); err != nil {
64+
files := map[string]string{
65+
"base/sqlc.yaml.tmpl": "sqlc.yaml",
66+
"db/init.sql.tmpl": fmt.Sprintf("internal/db/migrations/%s_init.sql", time.Now().Format("20060102150405")),
67+
"db/user.sql.tmpl": "internal/db/queries/user.sql",
68+
"db/db.go.tmpl": "internal/db/db.go",
69+
}
70+
if err := generateRequiredFiles(cfg, files); err != nil {
3571
return err
3672
}
3773
}
3874

3975
return nil
4076
}
4177

78+
func generateDirs(cfg *config.Config, dirs []string) error {
79+
for _, dir := range dirs {
80+
if err := os.MkdirAll(filepath.Join(cfg.OutputPath, dir), 0755); err != nil {
81+
return err
82+
}
83+
}
84+
return nil
85+
}
86+
4287
func generateBaseFiles(cfg *config.Config) error {
4388
dirs := []string{
4489
"cmd/server",
@@ -50,102 +95,60 @@ func generateBaseFiles(cfg *config.Config) error {
5095
dirs = append(dirs, "internal/db", "internal/db/generated", "internal/db/migrations", "internal/db/queries")
5196
}
5297

53-
for _, dir := range dirs {
54-
if err := os.MkdirAll(filepath.Join(cfg.OutputPath, dir), 0755); err != nil {
55-
return err
56-
}
98+
if err := generateDirs(cfg, dirs); err != nil {
99+
return err
57100
}
58101

59-
mainTemplates := []string{"base/main.go.tmpl"}
102+
// files to generate
103+
files := map[string]string{}
104+
60105
switch cfg.Form.ServerTypeFlag {
61106
case config.REST:
62-
mainTemplates = []string{"rest/main.go.tmpl"}
107+
files["rest/main.go.tmpl"] = "cmd/server/main.go"
63108
case config.GRPC:
64-
mainTemplates = []string{"grpc/main.go.tmpl"}
109+
files["grpc/main.go.tmpl"] = "cmd/server/main.go"
110+
case config.GraphQL:
111+
files["graphql/main.go.tmpl"] = "cmd/server/main.go"
65112
}
66113

67-
if err := generateFile(mainTemplates, filepath.Join(cfg.OutputPath, "cmd/server/main.go"), cfg); err != nil {
68-
return err
69-
}
70-
71-
if err := generateFile([]string{"base/config.go.tmpl"}, filepath.Join(cfg.OutputPath, "internal/config/config.go"), cfg); err != nil {
72-
return err
73-
}
74-
75-
if err := generateFile([]string{"base/logger.go.tmpl"}, filepath.Join(cfg.OutputPath, "internal/logger/logger.go"), cfg); err != nil {
76-
return err
77-
}
114+
files["base/config.go.tmpl"] = "internal/config/config.go"
115+
files["base/logger.go.tmpl"] = "internal/logger/logger.go"
78116

79117
if cfg.Form.MakefileFlag {
80-
if err := generateFile([]string{"base/Makefile.tmpl"}, filepath.Join(cfg.OutputPath, "Makefile"), cfg); err != nil {
81-
return err
82-
}
118+
files["base/Makefile.tmpl"] = "Makefile"
83119
}
84120

85121
if cfg.Form.DockerFlag {
86-
if err := generateFile([]string{"base/compose.yml.tmpl"}, filepath.Join(cfg.OutputPath, "docker-compose.yml"), cfg); err != nil {
87-
return err
88-
}
89-
90-
if err := generateFile([]string{"base/.env.example.tmpl"}, filepath.Join(cfg.OutputPath, ".env"), cfg); err != nil {
91-
return err
92-
}
122+
files["base/compose.yml.tmpl"] = "docker-compose.yml"
123+
files["base/.env.example.tmpl"] = ".env.example"
93124
}
94125

95-
return nil
96-
}
97-
98-
func generateRESTServer(cfg *config.Config) error {
99-
// specific go module
100-
if err := generateFile([]string{"rest/go.mod.tmpl"}, filepath.Join(cfg.OutputPath, "go.mod"), cfg); err != nil {
126+
if err := generateRequiredFiles(cfg, files); err != nil {
101127
return err
102128
}
103129

104-
apiFiles := map[string]string{
105-
"rest/server.go.tmpl": "internal/api/server.go",
106-
"rest/handler.go.tmpl": "internal/api/handler.go",
107-
"rest/service.go.tmpl": "internal/api/service.go",
108-
"rest/types.go.tmpl": "internal/api/types.go",
109-
}
110-
111-
for tmpl, out := range apiFiles {
112-
if err := generateFile([]string{tmpl}, filepath.Join(cfg.OutputPath, out), cfg); err != nil {
113-
return err
114-
}
115-
}
116-
117130
return nil
118131
}
119132

120-
func generateDBFiles(cfg *config.Config) error {
121-
dbFiles := map[string]string{
122-
"base/sqlc.yaml.tmpl": "sqlc.yaml",
123-
"db/init.sql.tmpl": fmt.Sprintf("internal/db/migrations/%s_init.sql", time.Now().Format("20060102150405")),
124-
"db/user.sql.tmpl": "internal/db/queries/user.sql",
125-
"db/db.go.tmpl": "internal/db/db.go",
126-
}
127-
128-
for tmpl, out := range dbFiles {
129-
if err := generateFile([]string{tmpl}, filepath.Join(cfg.OutputPath, out), cfg); err != nil {
133+
func generateRequiredFiles(cfg *config.Config, files map[string]string) error {
134+
for tmpl, out := range files {
135+
if err := generateSpecificFile([]string{tmpl}, filepath.Join(cfg.OutputPath, out), cfg); err != nil {
130136
return err
131137
}
132138
}
133-
134139
return nil
135140
}
136141

137-
func generateFile(tmplPath []string, outputPath string, data interface{}) error {
142+
func generateSpecificFile(tmplPath []string, outputPath string, data interface{}) error {
138143
tmpl, err := template.ParseFS(templates.FS, tmplPath...)
139144
if err != nil {
140145
return err
141146
}
142147

143-
// ensure the directory exists
144148
if err := os.MkdirAll(filepath.Dir(outputPath), 0755); err != nil {
145149
return err
146150
}
147151

148-
// create the file
149152
out, err := os.Create(outputPath)
150153
if err != nil {
151154
return err
@@ -158,24 +161,3 @@ func generateFile(tmplPath []string, outputPath string, data interface{}) error
158161

159162
return nil
160163
}
161-
162-
func generateGRPCServer(cfg *config.Config) error {
163-
// specific go module
164-
if err := generateFile([]string{"grpc/go.mod.tmpl"}, filepath.Join(cfg.OutputPath, "go.mod"), cfg); err != nil {
165-
return err
166-
}
167-
168-
apiFiles := map[string]string{
169-
"grpc/server.go.tmpl": "internal/api/server.go",
170-
"grpc/handler.go.tmpl": "internal/api/handler.go",
171-
"proto/user.proto.tmpl": "internal/pb/user/user.proto",
172-
}
173-
174-
for tmpl, out := range apiFiles {
175-
if err := generateFile([]string{tmpl}, filepath.Join(cfg.OutputPath, out), cfg); err != nil {
176-
return err
177-
}
178-
}
179-
180-
return nil
181-
}

internal/templates/base/Makefile.tmpl

Lines changed: 7 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/templates/base/logger.go.tmpl

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/templates/graphql/go.mod.tmpl

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)