-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhandlerOptions.go
More file actions
116 lines (101 loc) · 3.85 KB
/
handlerOptions.go
File metadata and controls
116 lines (101 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package shiftapi
import (
"net/http"
"reflect"
)
type routeConfig struct {
info *RouteInfo
status int
errors []errorEntry
middleware []func(http.Handler) http.Handler
staticRespHeaders []staticResponseHeader
contentType string // custom response media type
responseSchemaType reflect.Type // optional type for schema generation under the content type
eventVariants []SSEEventVariant // SSE event variants, set by registerSSERoute
}
func (c *routeConfig) addError(e errorEntry) {
c.errors = append(c.errors, e)
}
func (c *routeConfig) addMiddleware(mw []func(http.Handler) http.Handler) {
c.middleware = append(c.middleware, mw...)
}
func (c *routeConfig) addStaticResponseHeader(h staticResponseHeader) {
c.staticRespHeaders = append(c.staticRespHeaders, h)
}
func applyRouteOptions(opts []RouteOption) routeConfig {
cfg := routeConfig{status: http.StatusOK}
for _, opt := range opts {
opt.applyToRoute(&cfg)
}
return cfg
}
// RouteInfo provides metadata for a route that appears in the OpenAPI spec
// and the generated documentation UI.
type RouteInfo struct {
Summary string
Description string
Tags []string
}
// routeAndWSAndSSEOption implements RouteOption, WSOption, and SSEOption for
// options that need to work on Handle, HandleSSE, and HandleWS routes.
type routeAndWSAndSSEOption struct {
routeFn func(*routeConfig)
wsFn func(*wsRouteConfig)
sseFn func(*sseRouteConfig)
}
func (o routeAndWSAndSSEOption) applyToRoute(cfg *routeConfig) { o.routeFn(cfg) }
func (o routeAndWSAndSSEOption) applyToWS(cfg *wsRouteConfig) { o.wsFn(cfg) }
func (o routeAndWSAndSSEOption) applyToSSE(cfg *sseRouteConfig) { o.sseFn(cfg) }
// WithRouteInfo sets the route's OpenAPI metadata (summary, description, tags).
//
// shiftapi.Handle(api, "POST /greet", greet, shiftapi.WithRouteInfo(shiftapi.RouteInfo{
// Summary: "Greet a person",
// Tags: []string{"greetings"},
// }))
func WithRouteInfo(info RouteInfo) routeAndWSAndSSEOption {
return routeAndWSAndSSEOption{
routeFn: func(cfg *routeConfig) { cfg.info = &info },
wsFn: func(cfg *wsRouteConfig) { cfg.info = &info },
sseFn: func(cfg *sseRouteConfig) { cfg.info = &info },
}
}
// WithStatus sets the success HTTP status code for the route (default: 200).
// Use this for routes that should return 201 Created, 204 No Content, etc.
func WithStatus(status int) routeOptionFunc {
return func(cfg *routeConfig) {
cfg.status = status
}
}
// ResponseSchemaOption carries a type for deferred OpenAPI schema generation
// with [WithContentType].
type ResponseSchemaOption struct {
typ reflect.Type
}
// ResponseSchema captures the type T for OpenAPI schema generation. The actual
// schema is generated at registration time using the API's configured schema
// customizer, so enum lookups and validation constraints are applied correctly.
func ResponseSchema[T any]() ResponseSchemaOption {
return ResponseSchemaOption{typ: reflect.TypeFor[T]()}
}
// WithContentType sets a custom response content type for the route's OpenAPI
// spec. An optional [ResponseSchemaOption] produced by [ResponseSchema] can be
// passed to include a schema under the specified media type.
//
// For [HandleRaw] routes, this determines how the response appears in the
// OpenAPI spec. For [Handle] routes, this overrides the default
// "application/json" media type key.
//
// shiftapi.HandleRaw(api, "GET /events", sseHandler,
// shiftapi.WithContentType("text/event-stream"),
// )
// shiftapi.HandleRaw(api, "GET /events", sseHandler,
// shiftapi.WithContentType("text/event-stream", shiftapi.ResponseSchema[Event]()),
// )
func WithContentType(contentType string, opts ...ResponseSchemaOption) routeOptionFunc {
return func(cfg *routeConfig) {
cfg.contentType = contentType
if len(opts) > 0 {
cfg.responseSchemaType = opts[0].typ
}
}
}