Skip to content

Commit a6199a6

Browse files
committed
support multipe ops per path & cleanup
1 parent f143782 commit a6199a6

4 files changed

Lines changed: 164 additions & 143 deletions

File tree

handler.go

Lines changed: 6 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import (
66
"fmt"
77
"net/http"
88
"reflect"
9-
10-
"github.com/getkin/kin-openapi/openapi3"
119
)
1210

1311
type Handler interface {
@@ -50,7 +48,12 @@ func (h handler[RequestBody, ResponseBody]) unimplementable() {
5048
}
5149

5250
func (h handler[RequestBody, ResponseBody]) register(server *ShiftAPI) error {
53-
if err := h.updateSchema(server); err != nil {
51+
var requestBody RequestBody
52+
inType := reflect.TypeOf(requestBody)
53+
var responseBody ResponseBody
54+
outType := reflect.TypeOf(responseBody)
55+
56+
if err := server.updateSchema(h.method, h.path, inType, outType); err != nil {
5457
return err
5558
}
5659

@@ -60,97 +63,6 @@ func (h handler[RequestBody, ResponseBody]) register(server *ShiftAPI) error {
6063
return nil
6164
}
6265

63-
func (h handler[RequestBody, ResponseBody]) updateSchema(server *ShiftAPI) error {
64-
65-
var in RequestBody
66-
inType := reflect.TypeOf(in)
67-
inSchema, err := server.generateSchemaRef(inType)
68-
if err != nil {
69-
return err
70-
}
71-
72-
var out ResponseBody
73-
outType := reflect.TypeOf(out)
74-
outSchema, err := server.generateSchemaRef(outType)
75-
if err != nil {
76-
return err
77-
}
78-
responses := openapi3.NewResponses()
79-
responseContent := make(map[string]*openapi3.MediaType)
80-
responseContent["application/json"] = &openapi3.MediaType{
81-
Schema: &openapi3.SchemaRef{
82-
Ref: fmt.Sprintf("#/components/schemas/%s", outSchema.Ref),
83-
},
84-
}
85-
responses.Set("200", &openapi3.ResponseRef{
86-
Value: &openapi3.Response{
87-
Description: String("Success"),
88-
Content: responseContent,
89-
},
90-
})
91-
92-
requestContent := make(map[string]*openapi3.MediaType)
93-
requestContent["application/json"] = &openapi3.MediaType{
94-
Schema: &openapi3.SchemaRef{
95-
Ref: fmt.Sprintf("#/components/schemas/%s", inSchema.Ref),
96-
},
97-
}
98-
requestBody := &openapi3.RequestBodyRef{
99-
Value: &openapi3.RequestBody{
100-
Content: requestContent,
101-
},
102-
}
103-
104-
var oPath *openapi3.PathItem
105-
switch h.method {
106-
case http.MethodPost:
107-
oPath = &openapi3.PathItem{
108-
Post: &openapi3.Operation{
109-
// Summary: opts.Summary,
110-
RequestBody: requestBody,
111-
// Description: opts.Description,
112-
Responses: responses,
113-
},
114-
}
115-
}
116-
if oPath == nil {
117-
return fmt.Errorf("method '%s' not implemented", h.method)
118-
}
119-
server.spec.Paths.Set(h.path, oPath)
120-
// server.spec.Components.Responses.Default()
121-
122-
server.spec.Components.Schemas[inSchema.Ref] = &openapi3.SchemaRef{
123-
Value: inSchema.Value,
124-
}
125-
server.spec.Components.Schemas[outSchema.Ref] = &openapi3.SchemaRef{
126-
Value: outSchema.Value,
127-
}
128-
return nil
129-
}
130-
131-
func (s *ShiftAPI) generateSchemaRef(t reflect.Type) (*openapi3.SchemaRef, error) {
132-
schema, err := s.specGen.GenerateSchemaRef(t)
133-
if err != nil {
134-
return nil, err
135-
}
136-
137-
// TODO why tf does kin set ref values for basic types
138-
scrubRefs(schema)
139-
140-
return schema, nil
141-
}
142-
143-
func scrubRefs(s *openapi3.SchemaRef) {
144-
if s.Value.Properties == nil || len(s.Value.Properties) <= 0 {
145-
return
146-
}
147-
for _, p := range s.Value.Properties {
148-
if !p.Value.Type.Is("object") {
149-
p.Ref = ""
150-
}
151-
}
152-
}
153-
15466
func (h handler[RequestBody, ResponseBody]) stdHandler(ctx context.Context) http.HandlerFunc {
15567
return func(w http.ResponseWriter, r *http.Request) {
15668
// TODO: valdiate request body?
File renamed without changes.

schema.go

Lines changed: 94 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,111 @@
11
package shiftapi
22

33
import (
4+
"fmt"
5+
"net/http"
6+
"reflect"
7+
48
"github.com/getkin/kin-openapi/openapi3"
59
)
610

7-
type Info struct {
8-
Summary string
9-
Title string
10-
Description string
11-
TermsOfService string
12-
Contact *Contact
13-
License *License
14-
Version string
15-
}
11+
func (s *ShiftAPI) updateSchema(method, path string, inType, outType reflect.Type) error {
1612

17-
type Contact struct {
18-
Name string
19-
URL string
20-
Email string
21-
}
13+
inSchema, err := s.generateSchemaRef(inType)
14+
if err != nil {
15+
return err
16+
}
2217

23-
type License struct {
24-
Name string
25-
URL string
26-
Identifier string
27-
}
18+
outSchema, err := s.generateSchemaRef(outType)
19+
if err != nil {
20+
return err
21+
}
22+
responses := openapi3.NewResponses()
23+
responseContent := make(map[string]*openapi3.MediaType)
24+
responseContent["application/json"] = &openapi3.MediaType{
25+
Schema: &openapi3.SchemaRef{
26+
Ref: fmt.Sprintf("#/components/schemas/%s", outSchema.Ref),
27+
},
28+
}
29+
responses.Set("200", &openapi3.ResponseRef{
30+
Value: &openapi3.Response{
31+
Description: String("Success"),
32+
Content: responseContent,
33+
},
34+
})
2835

29-
func WithInfo(info Info) func(*ShiftAPI) *ShiftAPI {
30-
return func(api *ShiftAPI) *ShiftAPI {
31-
api.spec.Info = &openapi3.Info{
32-
Title: info.Title,
33-
Description: info.Description,
34-
Version: info.Version,
35-
}
36-
if info.Contact != nil {
37-
api.spec.Info.Contact = &openapi3.Contact{
38-
Name: info.Contact.Name,
39-
URL: info.Contact.URL,
40-
Email: info.Contact.Email,
41-
}
42-
}
43-
if info.License != nil {
44-
api.spec.Info.License = &openapi3.License{
45-
Name: info.License.Name,
46-
URL: info.License.URL,
47-
}
48-
}
49-
return api
36+
requestContent := make(map[string]*openapi3.MediaType)
37+
requestContent["application/json"] = &openapi3.MediaType{
38+
Schema: &openapi3.SchemaRef{
39+
Ref: fmt.Sprintf("#/components/schemas/%s", inSchema.Ref),
40+
},
41+
}
42+
requestBody := &openapi3.RequestBodyRef{
43+
Value: &openapi3.RequestBody{
44+
Content: requestContent,
45+
},
46+
}
47+
48+
pathItem := s.spec.Paths.Find(path)
49+
if pathItem == nil {
50+
pathItem = &openapi3.PathItem{}
51+
s.spec.Paths.Set(path, pathItem)
52+
}
53+
54+
op := &openapi3.Operation{
55+
// Summary: opts.Summary,
56+
RequestBody: requestBody,
57+
// Description: opts.Description,
58+
Responses: responses,
59+
}
60+
61+
switch method {
62+
case http.MethodGet:
63+
pathItem.Get = op
64+
case http.MethodPost:
65+
pathItem.Post = op
66+
case http.MethodPut:
67+
pathItem.Put = op
68+
case http.MethodDelete:
69+
pathItem.Delete = op
70+
case http.MethodPatch:
71+
pathItem.Patch = op
72+
case http.MethodHead:
73+
pathItem.Head = op
74+
case http.MethodOptions:
75+
pathItem.Options = op
76+
default:
77+
return fmt.Errorf("method '%s' not supported", method)
78+
}
79+
// s.spec.Components.Responses.Default()
80+
81+
s.spec.Components.Schemas[inSchema.Ref] = &openapi3.SchemaRef{
82+
Value: inSchema.Value,
83+
}
84+
s.spec.Components.Schemas[outSchema.Ref] = &openapi3.SchemaRef{
85+
Value: outSchema.Value,
5086
}
87+
return nil
5188
}
5289

53-
type ExternalDocs struct {
54-
Description string
55-
URL string
90+
func (s *ShiftAPI) generateSchemaRef(t reflect.Type) (*openapi3.SchemaRef, error) {
91+
schema, err := s.specGen.GenerateSchemaRef(t)
92+
if err != nil {
93+
return nil, err
94+
}
95+
96+
// TODO why tf does kin set ref values for basic types
97+
scrubRefs(schema)
98+
99+
return schema, nil
56100
}
57101

58-
func WithExternalDocs(externalDocs ExternalDocs) func(*ShiftAPI) *ShiftAPI {
59-
return func(api *ShiftAPI) *ShiftAPI {
60-
api.spec.ExternalDocs = &openapi3.ExternalDocs{
61-
Description: externalDocs.Description,
62-
URL: externalDocs.URL,
102+
func scrubRefs(s *openapi3.SchemaRef) {
103+
if s.Value.Properties == nil || len(s.Value.Properties) <= 0 {
104+
return
105+
}
106+
for _, p := range s.Value.Properties {
107+
if !p.Value.Type.Is("object") {
108+
p.Ref = ""
63109
}
64-
return api
65110
}
66111
}

serverOptions.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package shiftapi
2+
3+
import "github.com/getkin/kin-openapi/openapi3"
4+
5+
type Info struct {
6+
Summary string
7+
Title string
8+
Description string
9+
TermsOfService string
10+
Contact *Contact
11+
License *License
12+
Version string
13+
}
14+
15+
type Contact struct {
16+
Name string
17+
URL string
18+
Email string
19+
}
20+
21+
type License struct {
22+
Name string
23+
URL string
24+
Identifier string
25+
}
26+
27+
func WithInfo(info Info) func(*ShiftAPI) *ShiftAPI {
28+
return func(api *ShiftAPI) *ShiftAPI {
29+
api.spec.Info = &openapi3.Info{
30+
Title: info.Title,
31+
Description: info.Description,
32+
Version: info.Version,
33+
}
34+
if info.Contact != nil {
35+
api.spec.Info.Contact = &openapi3.Contact{
36+
Name: info.Contact.Name,
37+
URL: info.Contact.URL,
38+
Email: info.Contact.Email,
39+
}
40+
}
41+
if info.License != nil {
42+
api.spec.Info.License = &openapi3.License{
43+
Name: info.License.Name,
44+
URL: info.License.URL,
45+
}
46+
}
47+
return api
48+
}
49+
}
50+
51+
type ExternalDocs struct {
52+
Description string
53+
URL string
54+
}
55+
56+
func WithExternalDocs(externalDocs ExternalDocs) func(*ShiftAPI) *ShiftAPI {
57+
return func(api *ShiftAPI) *ShiftAPI {
58+
api.spec.ExternalDocs = &openapi3.ExternalDocs{
59+
Description: externalDocs.Description,
60+
URL: externalDocs.URL,
61+
}
62+
return api
63+
}
64+
}

0 commit comments

Comments
 (0)