Skip to content

Commit 7008d4e

Browse files
committed
hacky handler options
1 parent a6199a6 commit 7008d4e

6 files changed

Lines changed: 92 additions & 65 deletions

File tree

examples/greeter/main.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,19 @@ func greet(ctx context.Context, headers http.Header, person *Person) (*Greeting,
2828

2929
func main() {
3030
ctx := context.Background()
31-
server := shiftapi.New(ctx, shiftapi.WithInfo(shiftapi.Info{
31+
server := shiftapi.New(ctx, shiftapi.WithServerInfo(shiftapi.ServerInfo{
3232
Title: "Geeter Demo API",
3333
}))
3434

35-
handleGreet := shiftapi.Post("/greet", greet)
35+
handleGreet := shiftapi.Post(
36+
"/greet",
37+
greet,
38+
shiftapi.WithHandlerInfo(&shiftapi.HandlerInfo{
39+
Summary: "Greet a person",
40+
Description: "Greet a person with a friendly greeting",
41+
Tags: []string{"greet"},
42+
}),
43+
)
3644
if err := server.Register(handleGreet); err != nil {
3745
log.Fatal(err)
3846
}

handler.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@ type Handler interface {
1717
unimplementable()
1818
}
1919

20-
type HandlerOption interface {
21-
// unimplementable is a method that should never be called.
22-
// It is simply used to ensure that the HandlerOption interface can only be implemented
23-
// internally by the shiftapi package.
24-
unimplementable()
25-
}
20+
type HandlerOption func(Handler) Handler
2621

2722
type ValidBody any // TODO can we type constrain to a struct?
2823

@@ -37,7 +32,8 @@ type handler[RequestBody ValidBody, ResponseBody ValidBody] struct {
3732
method string
3833
path string
3934
handlerFunc HandlerFunc[RequestBody, ResponseBody]
40-
options []func(HandlerFunc[RequestBody, ResponseBody]) HandlerFunc[RequestBody, ResponseBody]
35+
36+
info *HandlerInfo
4137
}
4238

4339
// ensure handler implements Handler at compile time
@@ -53,7 +49,13 @@ func (h handler[RequestBody, ResponseBody]) register(server *ShiftAPI) error {
5349
var responseBody ResponseBody
5450
outType := reflect.TypeOf(responseBody)
5551

56-
if err := server.updateSchema(h.method, h.path, inType, outType); err != nil {
52+
if err := server.updateSchema(
53+
h.method,
54+
h.path,
55+
inType,
56+
outType,
57+
h.info,
58+
); err != nil {
5759
return err
5860
}
5961

handlerFuncs.go

Lines changed: 36 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,87 +2,74 @@ package shiftapi
22

33
import "net/http"
44

5-
func Get[RequestBody ValidBody, ResponseBody ValidBody](
5+
func method[RequestBody ValidBody, ResponseBody ValidBody](
6+
method string,
67
path string,
78
handlerFunc HandlerFunc[RequestBody, ResponseBody],
8-
options ...func(HandlerFunc[RequestBody, ResponseBody]) HandlerFunc[RequestBody, ResponseBody],
9-
) Handler {
10-
return &handler[RequestBody, ResponseBody]{
11-
method: http.MethodGet,
9+
options ...HandlerOption,
10+
) *handler[RequestBody, ResponseBody] {
11+
h := &handler[RequestBody, ResponseBody]{
12+
method: method,
1213
path: path,
1314
handlerFunc: handlerFunc,
14-
options: options,
1515
}
16+
for _, option := range options {
17+
option(h)
18+
}
19+
return h
20+
}
21+
22+
func Get[RequestBody ValidBody, ResponseBody ValidBody](
23+
path string,
24+
handlerFunc HandlerFunc[RequestBody, ResponseBody],
25+
options ...HandlerOption,
26+
) *handler[RequestBody, ResponseBody] {
27+
return method(http.MethodGet, path, handlerFunc, options...)
1628
}
1729

1830
func Post[RequestBody ValidBody, ResponseBody ValidBody](
1931
path string,
2032
handlerFunc HandlerFunc[RequestBody, ResponseBody],
21-
options ...func(HandlerFunc[RequestBody, ResponseBody]) HandlerFunc[RequestBody, ResponseBody],
22-
) Handler {
23-
return &handler[RequestBody, ResponseBody]{
24-
method: http.MethodPost,
25-
path: path,
26-
handlerFunc: handlerFunc,
27-
options: options,
28-
}
33+
options ...HandlerOption,
34+
) *handler[RequestBody, ResponseBody] {
35+
return method(http.MethodPost, path, handlerFunc, options...)
2936
}
3037

3138
func Put[RequestBody ValidBody, ResponseBody ValidBody](
3239
path string,
3340
handlerFunc HandlerFunc[RequestBody, ResponseBody],
34-
options ...func(HandlerFunc[RequestBody, ResponseBody]) HandlerFunc[RequestBody, ResponseBody],
35-
) Handler {
36-
return &handler[RequestBody, ResponseBody]{
37-
method: http.MethodPut,
38-
path: path,
39-
handlerFunc: handlerFunc,
40-
}
41+
options ...HandlerOption,
42+
) *handler[RequestBody, ResponseBody] {
43+
return method(http.MethodPut, path, handlerFunc, options...)
4144
}
4245
func Patch[RequestBody ValidBody, ResponseBody ValidBody](
4346
path string,
4447
handlerFunc HandlerFunc[RequestBody, ResponseBody],
45-
options ...func(HandlerFunc[RequestBody, ResponseBody]) HandlerFunc[RequestBody, ResponseBody],
46-
) Handler {
47-
return &handler[RequestBody, ResponseBody]{
48-
method: http.MethodPatch,
49-
path: path,
50-
handlerFunc: handlerFunc,
51-
}
48+
options ...HandlerOption,
49+
) *handler[RequestBody, ResponseBody] {
50+
return method(http.MethodPatch, path, handlerFunc, options...)
5251
}
5352

5453
func Delete[RequestBody ValidBody, ResponseBody ValidBody](
5554
path string,
5655
handlerFunc HandlerFunc[RequestBody, ResponseBody],
57-
options ...func(HandlerFunc[RequestBody, ResponseBody]) HandlerFunc[RequestBody, ResponseBody],
58-
) Handler {
59-
return &handler[RequestBody, ResponseBody]{
60-
method: http.MethodDelete,
61-
path: path,
62-
handlerFunc: handlerFunc,
63-
}
56+
options ...HandlerOption,
57+
) *handler[RequestBody, ResponseBody] {
58+
return method(http.MethodDelete, path, handlerFunc, options...)
6459
}
6560

6661
func Head[RequestBody ValidBody, ResponseBody ValidBody](
6762
path string,
6863
handlerFunc HandlerFunc[RequestBody, ResponseBody],
69-
options ...func(HandlerFunc[RequestBody, ResponseBody]) HandlerFunc[RequestBody, ResponseBody],
70-
) Handler {
71-
return &handler[RequestBody, ResponseBody]{
72-
method: http.MethodHead,
73-
path: path,
74-
handlerFunc: handlerFunc,
75-
}
64+
options ...HandlerOption,
65+
) *handler[RequestBody, ResponseBody] {
66+
return method(http.MethodHead, path, handlerFunc, options...)
7667
}
7768

7869
func Options[RequestBody ValidBody, ResponseBody ValidBody](
7970
path string,
8071
handlerFunc HandlerFunc[RequestBody, ResponseBody],
81-
options ...func(HandlerFunc[RequestBody, ResponseBody]) HandlerFunc[RequestBody, ResponseBody],
82-
) Handler {
83-
return &handler[RequestBody, ResponseBody]{
84-
method: http.MethodOptions,
85-
path: path,
86-
handlerFunc: handlerFunc,
87-
}
72+
options ...HandlerOption,
73+
) *handler[RequestBody, ResponseBody] {
74+
return method(http.MethodOptions, path, handlerFunc, options...)
8875
}

handlerOptions.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package shiftapi
2+
3+
type HandlerInfo struct {
4+
Summary string
5+
Description string
6+
Tags []string
7+
}
8+
9+
type optionsApplier interface {
10+
setInfo(*HandlerInfo)
11+
}
12+
13+
func (h *handler[RequestBody, ResponseBody]) setInfo(info *HandlerInfo) {
14+
h.info = info
15+
}
16+
17+
var _ optionsApplier = (*handler[ValidBody, ValidBody])(nil)
18+
19+
func WithHandlerInfo(info *HandlerInfo) HandlerOption {
20+
return func(h Handler) Handler {
21+
if handler, ok := h.(optionsApplier); ok {
22+
handler.setInfo(info)
23+
return h
24+
}
25+
panic("invalid handler type, this should never happen, please open an issue on github")
26+
}
27+
}

schema.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"github.com/getkin/kin-openapi/openapi3"
99
)
1010

11-
func (s *ShiftAPI) updateSchema(method, path string, inType, outType reflect.Type) error {
11+
func (s *ShiftAPI) updateSchema(method, path string, inType, outType reflect.Type, handlerInfo *HandlerInfo) error {
1212

1313
inSchema, err := s.generateSchemaRef(inType)
1414
if err != nil {
@@ -52,10 +52,13 @@ func (s *ShiftAPI) updateSchema(method, path string, inType, outType reflect.Typ
5252
}
5353

5454
op := &openapi3.Operation{
55-
// Summary: opts.Summary,
5655
RequestBody: requestBody,
57-
// Description: opts.Description,
58-
Responses: responses,
56+
Responses: responses,
57+
}
58+
if handlerInfo != nil {
59+
op.Summary = handlerInfo.Summary
60+
op.Description = handlerInfo.Description
61+
op.Tags = handlerInfo.Tags
5962
}
6063

6164
switch method {

serverOptions.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package shiftapi
22

33
import "github.com/getkin/kin-openapi/openapi3"
44

5-
type Info struct {
5+
type ServerInfo struct {
66
Summary string
77
Title string
88
Description string
@@ -24,7 +24,7 @@ type License struct {
2424
Identifier string
2525
}
2626

27-
func WithInfo(info Info) func(*ShiftAPI) *ShiftAPI {
27+
func WithServerInfo(info ServerInfo) func(*ShiftAPI) *ShiftAPI {
2828
return func(api *ShiftAPI) *ShiftAPI {
2929
api.spec.Info = &openapi3.Info{
3030
Title: info.Title,

0 commit comments

Comments
 (0)