Skip to content

Commit e4abfe0

Browse files
committed
feat: enhance OpenAPI support by adding base package name to spec generation and updating endpoint registration with additional metadata
1 parent a452dce commit e4abfe0

10 files changed

Lines changed: 195 additions & 152 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ go.work
2222
tmp/
2323

2424
coverage.*
25+
openapi.gen.json

app.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@ type App struct {
1515
endpoints []*Endpoint
1616
}
1717

18-
func New(frameworkName ...string) *App {
19-
frameworkName = append(frameworkName, "fiber")
18+
func New(frameworkName, basePkgName string) *App {
2019

2120
s := &App{
22-
framework: framework.GetFramework(frameworkName[0]),
23-
spec: spec.New(),
21+
framework: framework.GetFramework(frameworkName),
22+
spec: spec.New(basePkgName),
2423
endpoints: []*Endpoint{},
2524
}
2625
addOpenAPIRoutes(s)
@@ -65,9 +64,10 @@ func (s *App) Sync() {
6564
for _, e := range s.endpoints {
6665
s.framework.Register(e.path, e.method, s.createHandler(e.handlers...))
6766
if e.addToSpec {
68-
s.spec.Register(s.framework.GetOpenAPICompatiblePathPattern(e.path), e.method, e.tags, e.handlers...)
67+
s.spec.Register(s.framework.GetOpenAPICompatiblePathPattern(e.path), e.method, e.tags, e.operationId, e.summary, e.description, e.handlers...)
6968
}
7069
}
70+
s.spec.Write("openapi.gen.json")
7171
}
7272

7373
func (s *App) ListenAndServe(addr string) error {

pkg/spec/main.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package spec
22

33
import (
4+
"encoding/json"
45
"net/http"
6+
"os"
57
"reflect"
68
"strings"
79

@@ -14,7 +16,7 @@ type Spec struct {
1416
gen *openapi3gen.Generator
1517
}
1618

17-
func New() *Spec {
19+
func New(basePkgName string) *Spec {
1820
return &Spec{
1921
spec: &openapi3.T{
2022
OpenAPI: "3.1.0",
@@ -69,7 +71,7 @@ func New() *Spec {
6971

7072
name = t.PkgPath() + "_" + name
7173

72-
name = strings.ReplaceAll(name, "github.com/go-simpl/simplapi/example/", "")
74+
name = strings.ReplaceAll(name, basePkgName, "")
7375
name = strings.ReplaceAll(name, "/", "_")
7476

7577
return name
@@ -82,7 +84,7 @@ func (s *Spec) ToJson() any {
8284
return s.spec
8385
}
8486

85-
func (s *Spec) Register(path string, method string, tags []string, handlers ...interface{}) {
87+
func (s *Spec) Register(path string, method string, tags []string, operationId, summary, description string, handlers ...interface{}) {
8688
if s.spec.Paths.Find(path) == nil {
8789
s.spec.Paths.Set(path, &openapi3.PathItem{})
8890
}
@@ -93,6 +95,10 @@ func (s *Spec) Register(path string, method string, tags []string, handlers ...i
9395
op.Tags = tags
9496
}
9597

98+
op.OperationID = operationId
99+
op.Summary = summary
100+
op.Description = description
101+
96102
for _, h := range handlers {
97103
addRequestInfo(s.gen, s.spec.Components.Schemas, op, h)
98104
}
@@ -114,3 +120,11 @@ func (s *Spec) Register(path string, method string, tags []string, handlers ...i
114120
s.spec.Paths.Value(path).Patch = op
115121
}
116122
}
123+
124+
func (s *Spec) Write(path string) error {
125+
json, err := json.MarshalIndent(s.spec, "", " ")
126+
if err != nil {
127+
return err
128+
}
129+
return os.WriteFile(path, json, 0644)
130+
}

tests/basics_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func TestNoRoutes(t *testing.T) {
1818
frameworks := utils.GetAllFrameworks()
1919
for _, framework := range frameworks {
2020
t.Run(framework, func(t *testing.T) {
21-
app := simplapi.New(framework)
21+
app := simplapi.New(framework, "")
2222
fApp := app.GetApp()
2323

2424
req := httptest.NewRequest(http.MethodGet, "/", nil)
@@ -43,7 +43,7 @@ func TestGET(t *testing.T) {
4343
frameworks := utils.GetAllFrameworks()
4444
for _, framework := range frameworks {
4545
t.Run(framework, func(t *testing.T) {
46-
app := simplapi.New(framework)
46+
app := simplapi.New(framework, "")
4747
fApp := app.GetApp()
4848

4949
app.GET("/", func() (*HelloResponse, error) {
@@ -72,7 +72,7 @@ func TestListen(t *testing.T) {
7272
frameworks := utils.GetAllFrameworks()
7373
for _, framework := range frameworks {
7474
t.Run(framework, func(t *testing.T) {
75-
app := simplapi.New(framework)
75+
app := simplapi.New(framework, "")
7676

7777
app.GET("/", func() (*HelloResponse, error) {
7878
return &HelloResponse{

tests/chain_tests/chain_test.go

Lines changed: 120 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
simplapi "github.com/go-simpl/simplapi"
1313
"github.com/go-simpl/simplapi/pkg/context"
14+
"github.com/go-simpl/simplapi/tests/utils"
1415

1516
_ "github.com/go-simpl/simplapi/pkg/framework/fiberframework"
1617
)
@@ -24,142 +25,163 @@ func (*HelloResponse) GetStatusCode() int {
2425
}
2526

2627
func TestChainReturnedFromFirstFunc(t *testing.T) {
27-
app := simplapi.New()
28-
fApp := app.GetApp()
28+
frameworks := utils.GetAllFrameworks()
29+
for _, framework := range frameworks {
30+
t.Run(framework, func(t *testing.T) {
31+
app := simplapi.New(framework, "")
32+
fApp := app.GetApp()
2933

30-
func1 := func() (*HelloResponse, error) {
31-
return &HelloResponse{Message: "func1"}, nil
32-
}
34+
func1 := func() (*HelloResponse, error) {
35+
return &HelloResponse{Message: "func1"}, nil
36+
}
3337

34-
func2 := func() (*HelloResponse, error) {
35-
return &HelloResponse{Message: "func2"}, nil
36-
}
38+
func2 := func() (*HelloResponse, error) {
39+
return &HelloResponse{Message: "func2"}, nil
40+
}
3741

38-
app.GET("/", func1, func2)
39-
app.Sync()
42+
app.GET("/", func1, func2)
43+
app.Sync()
4044

41-
req, err := http.NewRequest("GET", "/", nil)
42-
assert.NoError(t, err)
45+
req, err := http.NewRequest("GET", "/", nil)
46+
assert.NoError(t, err)
4347

44-
response, err := fApp.TestRequest(req)
45-
assert.NoError(t, err)
48+
response, err := fApp.TestRequest(req)
49+
assert.NoError(t, err)
4650

47-
assert.Equal(t, http.StatusOK, response.StatusCode)
51+
assert.Equal(t, http.StatusOK, response.StatusCode)
4852

49-
bodyBytes, err := io.ReadAll(response.Body)
50-
assert.NoError(t, err)
51-
bodyString := string(bodyBytes)
52-
assert.Equal(t, `{"message":"func1"}`, bodyString)
53+
bodyBytes, err := io.ReadAll(response.Body)
54+
assert.NoError(t, err)
55+
bodyString := string(bodyBytes)
56+
assert.Equal(t, `{"message":"func1"}`, bodyString)
57+
})
58+
}
5359
}
5460

5561
func TestChainReturnedFromSecondFunc(t *testing.T) {
56-
app := simplapi.New()
57-
fApp := app.GetApp()
62+
frameworks := utils.GetAllFrameworks()
63+
for _, framework := range frameworks {
64+
t.Run(framework, func(t *testing.T) {
65+
app := simplapi.New(framework, "")
66+
fApp := app.GetApp()
5867

59-
func1 := func() (*HelloResponse, error) {
60-
return nil, nil
61-
}
68+
func1 := func() (*HelloResponse, error) {
69+
return nil, nil
70+
}
6271

63-
func2 := func() (*HelloResponse, error) {
64-
return &HelloResponse{Message: "func2"}, nil
65-
}
72+
func2 := func() (*HelloResponse, error) {
73+
return &HelloResponse{Message: "func2"}, nil
74+
}
6675

67-
app.GET("/", func1, func2)
68-
app.Sync()
76+
app.GET("/", func1, func2)
77+
app.Sync()
6978

70-
req, err := http.NewRequest("GET", "/", nil)
71-
assert.NoError(t, err)
79+
req, err := http.NewRequest("GET", "/", nil)
80+
assert.NoError(t, err)
7281

73-
response, err := fApp.TestRequest(req)
74-
assert.NoError(t, err)
82+
response, err := fApp.TestRequest(req)
83+
assert.NoError(t, err)
7584

76-
assert.Equal(t, http.StatusOK, response.StatusCode)
85+
assert.Equal(t, http.StatusOK, response.StatusCode)
7786

78-
bodyBytes, err := io.ReadAll(response.Body)
79-
assert.NoError(t, err)
80-
bodyString := string(bodyBytes)
81-
assert.Equal(t, `{"message":"func2"}`, bodyString)
87+
bodyBytes, err := io.ReadAll(response.Body)
88+
assert.NoError(t, err)
89+
bodyString := string(bodyBytes)
90+
assert.Equal(t, `{"message":"func2"}`, bodyString)
91+
})
92+
}
8293
}
8394

8495
func TestChainReturnedFromNoFunc(t *testing.T) {
85-
app := simplapi.New()
86-
fApp := app.GetApp()
96+
frameworks := utils.GetAllFrameworks()
97+
for _, framework := range frameworks {
98+
t.Run(framework, func(t *testing.T) {
99+
app := simplapi.New(framework, "")
100+
fApp := app.GetApp()
87101

88-
func1 := func() (*HelloResponse, error) {
89-
return nil, nil
90-
}
102+
func1 := func() (*HelloResponse, error) {
103+
return nil, nil
104+
}
91105

92-
func2 := func() (*HelloResponse, error) {
93-
return nil, nil
94-
}
106+
func2 := func() (*HelloResponse, error) {
107+
return nil, nil
108+
}
95109

96-
app.GET("/", func1, func2)
97-
app.Sync()
110+
app.GET("/", func1, func2)
111+
app.Sync()
98112

99-
req, err := http.NewRequest("GET", "/", nil)
100-
assert.NoError(t, err)
113+
req, err := http.NewRequest("GET", "/", nil)
114+
assert.NoError(t, err)
101115

102-
response, err := fApp.TestRequest(req)
103-
assert.NoError(t, err)
116+
response, err := fApp.TestRequest(req)
117+
assert.NoError(t, err)
104118

105-
assert.Equal(t, http.StatusOK, response.StatusCode)
119+
assert.Equal(t, http.StatusOK, response.StatusCode)
120+
})
121+
}
106122
}
107123

108124
func TestChainReturnedErrorFromFirstFunc(t *testing.T) {
109-
app := simplapi.New()
110-
fApp := app.GetApp()
125+
frameworks := utils.GetAllFrameworks()
126+
for _, framework := range frameworks {
127+
t.Run(framework, func(t *testing.T) {
128+
app := simplapi.New(framework, "")
129+
fApp := app.GetApp()
111130

112-
func1 := func() (*HelloResponse, error) {
113-
return nil, errors.New("server error")
114-
}
131+
func1 := func() (*HelloResponse, error) {
132+
return nil, errors.New("server error")
133+
}
115134

116-
func2 := func() (*HelloResponse, error) {
117-
return nil, nil
118-
}
135+
func2 := func() (*HelloResponse, error) {
136+
return nil, nil
137+
}
119138

120-
app.GET("/", func1, func2)
121-
app.Sync()
139+
app.GET("/", func1, func2)
140+
app.Sync()
122141

123-
req, err := http.NewRequest("GET", "/", nil)
124-
assert.NoError(t, err)
142+
req, err := http.NewRequest("GET", "/", nil)
143+
assert.NoError(t, err)
125144

126-
response, err := fApp.TestRequest(req)
127-
assert.NoError(t, err)
145+
response, err := fApp.TestRequest(req)
146+
assert.NoError(t, err)
128147

129-
assert.Equal(t, http.StatusInternalServerError, response.StatusCode)
148+
assert.Equal(t, http.StatusInternalServerError, response.StatusCode)
149+
})
150+
}
130151

131-
bodyBytes, err := io.ReadAll(response.Body)
132-
assert.NoError(t, err)
133-
bodyString := string(bodyBytes)
134-
assert.Equal(t, `server error`, bodyString)
135152
}
136153

137154
func TestContextInChain(t *testing.T) {
138-
app := simplapi.New()
139-
fApp := app.GetApp()
140-
141-
func1 := func(ctx *context.Context) (*HelloResponse, error) {
142-
ctx.Set("test", "test")
143-
return nil, nil
144-
}
145-
146-
func2 := func(ctx *context.Context) (*HelloResponse, error) {
147-
assert.Equal(t, "test", ctx.Get("test"))
148-
ctx.Delete("test")
149-
return nil, nil
155+
frameworks := utils.GetAllFrameworks()
156+
for _, framework := range frameworks {
157+
t.Run(framework, func(t *testing.T) {
158+
app := simplapi.New(framework, "")
159+
fApp := app.GetApp()
160+
161+
func1 := func(ctx *context.Context) (*HelloResponse, error) {
162+
ctx.Set("test", "test")
163+
return nil, nil
164+
}
165+
166+
func2 := func(ctx *context.Context) (*HelloResponse, error) {
167+
assert.Equal(t, "test", ctx.Get("test"))
168+
ctx.Delete("test")
169+
return nil, nil
170+
}
171+
172+
func3 := func(ctx *context.Context) (*HelloResponse, error) {
173+
assert.False(t, ctx.Contains("test"))
174+
return &HelloResponse{Message: ""}, nil
175+
}
176+
177+
app.GET("/", func1, func2, func3)
178+
app.Sync()
179+
180+
req := httptest.NewRequest("GET", "/", nil)
181+
response, err := fApp.TestRequest(req)
182+
assert.NoError(t, err)
183+
184+
assert.Equal(t, http.StatusOK, response.StatusCode)
185+
})
150186
}
151-
152-
func3 := func(ctx *context.Context) (*HelloResponse, error) {
153-
assert.False(t, ctx.Contains("test"))
154-
return &HelloResponse{Message: ""}, nil
155-
}
156-
157-
app.GET("/", func1, func2, func3)
158-
app.Sync()
159-
160-
req := httptest.NewRequest("GET", "/", nil)
161-
response, err := fApp.TestRequest(req)
162-
assert.NoError(t, err)
163-
164-
assert.Equal(t, http.StatusOK, response.StatusCode)
165187
}

tests/injection_tests/utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
)
1212

1313
func SetupTest(frameworkName string, method string) *simplapi.App {
14-
return simplapi.New(frameworkName)
14+
return simplapi.New(frameworkName, "")
1515
}
1616

1717
type HelloResponse struct {

0 commit comments

Comments
 (0)