-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
group.go
111 lines (91 loc) · 3.13 KB
/
group.go
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
package versioning
import "net/http"
// Group is a group of version-based routes.
// One version per one or more routes.
type Group struct {
version string
routes map[string]Map // key = path, value = map[version] = handler
deprecation DeprecationOptions
}
// NewGroup returns a ptr to Group based on the given "version".
//
// See `Handle` and `RegisterGroups` for more.
func NewGroup(version string) *Group {
return &Group{
version: version,
routes: make(map[string]Map),
}
}
// Deprecated marks this group and all its versioned routes
// as deprecated versions of that endpoint.
// It can be called in the end just before `RegisterGroups`
// or first by `NewGroup(...).Deprecated(...)`. It returns itself.
func (g *Group) Deprecated(options DeprecationOptions) *Group {
// if `Deprecated` is called in the end.
for _, versions := range g.routes {
versions[g.version] = Deprecated(versions[g.version], options)
}
// store the options if called before registering any versioned routes.
g.deprecation = options
return g
}
func (g *Group) addVRoute(path string, handler http.Handler) {
if _, exists := g.routes[path]; !exists {
g.routes[path] = Map{g.version: handler}
}
}
// Handle registers a versioned route to the group.
// A call of `RegisterGroups` is necessary in order to register the actual routes
// when the group is complete.
//
// See `RegisterGroups` for more.
func (g *Group) Handle(path string, handler http.Handler) {
if g.deprecation.ShouldHandle() { // if `Deprecated` called first.
handler = Deprecated(handler, g.deprecation)
}
g.addVRoute(path, handler)
}
// HandleFunc registers a versioned route to the group.
// A call of `RegisterGroups` is necessary in order to register the actual routes
// when the group is complete.
//
// See `RegisterGroups` for more.
func (g *Group) HandleFunc(path string, handlerFn func(w http.ResponseWriter, r *http.Request)) {
var handler http.Handler = http.HandlerFunc(handlerFn)
if g.deprecation.ShouldHandle() { // if `Deprecated` called first.
handler = Deprecated(handler, g.deprecation)
}
g.addVRoute(path, handler)
}
// StdMux is an interface which types like `net/http#ServeMux`
// implements in order to register handlers per path.
//
// See `RegisterGroups`.
type StdMux interface{ Handle(string, http.Handler) }
// RegisterGroups registers one or more groups to an `net/http#ServeMux` if not nil, and returns the routes.
// Map's key is the request path from `Group#Handle` and value is the `http.Handler`.
// See `NewGroup` and `NotFoundHandler` too.
func RegisterGroups(mux StdMux, notFoundHandler http.Handler, groups ...*Group) map[string]http.Handler {
total := make(map[string]Map)
routes := make(map[string]http.Handler)
for _, g := range groups {
for path, versions := range g.routes {
if _, exists := total[path]; exists {
total[path][g.version] = versions[g.version]
} else {
total[path] = versions
}
}
}
for path, versions := range total {
if notFoundHandler != nil {
versions[NotFound] = notFoundHandler
}
matcher := NewMatcher(versions)
if mux != nil {
mux.Handle(path, matcher)
}
routes[path] = matcher
}
return routes
}