/
group.go
185 lines (154 loc) · 5.19 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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package versioning
import (
"net/http"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/core/router"
)
type (
vroute struct {
method string
path string
versions Map
}
// Group is a group of version-based routes.
// One version per one or more routes.
Group struct {
version string
extraMethods []string
routes []vroute
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,
}
}
// 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 _, r := range g.routes {
r.versions[g.version] = Deprecated(r.versions[g.version], options)
}
// store the options if called before registering any versioned routes.
g.deprecation = options
return g
}
// AllowMethods can be called before `Handle/Get/Post...`
// to tell the underline router that all routes should be registered
// to these "methods" as well.
func (g *Group) AllowMethods(methods ...string) *Group {
g.extraMethods = append(g.extraMethods, methods...)
return g
}
func (g *Group) addVRoute(method, path string, handler context.Handler) {
for _, r := range g.routes { // check if route already exists.
if r.method == method && r.path == path {
return
}
}
g.routes = append(g.routes, vroute{
method: method,
path: path,
versions: 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.
//
// `RegisterGroups` for more.
func (g *Group) Handle(method string, path string, handler context.Handler) {
if g.deprecation.ShouldHandle() { // if `Deprecated` called first.
handler = Deprecated(handler, g.deprecation)
}
methods := append(g.extraMethods, method)
for _, method := range methods {
g.addVRoute(method, path, handler)
}
}
// None registers an "offline" versioned route
// see `context#ExecRoute(routeName)` and routing examples.
func (g *Group) None(path string, handler context.Handler) {
g.Handle(router.MethodNone, path, handler)
}
// Get registers a versioned route for the Get http method.
func (g *Group) Get(path string, handler context.Handler) {
g.Handle(http.MethodGet, path, handler)
}
// Post registers a versioned route for the Post http method.
func (g *Group) Post(path string, handler context.Handler) {
g.Handle(http.MethodPost, path, handler)
}
// Put registers a versioned route for the Put http method
func (g *Group) Put(path string, handler context.Handler) {
g.Handle(http.MethodPut, path, handler)
}
// Delete registers a versioned route for the Delete http method.
func (g *Group) Delete(path string, handler context.Handler) {
g.Handle(http.MethodDelete, path, handler)
}
// Connect registers a versioned route for the Connect http method.
func (g *Group) Connect(path string, handler context.Handler) {
g.Handle(http.MethodConnect, path, handler)
}
// Head registers a versioned route for the Head http method.
func (g *Group) Head(path string, handler context.Handler) {
g.Handle(http.MethodHead, path, handler)
}
// Options registers a versioned route for the Options http method.
func (g *Group) Options(path string, handler context.Handler) {
g.Handle(http.MethodOptions, path, handler)
}
// Patch registers a versioned route for the Patch http method.
func (g *Group) Patch(path string, handler context.Handler) {
g.Handle(http.MethodPatch, path, handler)
}
// Trace registers a versioned route for the Trace http method.
func (g *Group) Trace(path string, handler context.Handler) {
g.Handle(http.MethodTrace, path, handler)
}
// Any registers a versioned route for ALL of the http methods
// (Get,Post,Put,Head,Patch,Options,Connect,Delete).
func (g *Group) Any(registeredPath string, handler context.Handler) {
g.Get(registeredPath, handler)
g.Post(registeredPath, handler)
g.Put(registeredPath, handler)
g.Delete(registeredPath, handler)
g.Connect(registeredPath, handler)
g.Head(registeredPath, handler)
g.Options(registeredPath, handler)
g.Patch(registeredPath, handler)
g.Trace(registeredPath, handler)
}
// RegisterGroups registers one or more groups to an `iris.Party` or to the root router.
// See `NewGroup` and `NotFoundHandler` too.
func RegisterGroups(r router.Party, notFoundHandler context.Handler, groups ...*Group) (actualRoutes []*router.Route) {
var total []vroute
for _, g := range groups {
inner:
for _, r := range g.routes {
for i, tr := range total {
if tr.method == r.method && tr.path == r.path {
total[i].versions[g.version] = r.versions[g.version]
continue inner
}
}
total = append(total, r)
}
}
for _, vr := range total {
if notFoundHandler != nil {
vr.versions[NotFound] = notFoundHandler
}
route := r.Handle(vr.method, vr.path, NewMatcher(vr.versions))
actualRoutes = append(actualRoutes, route)
}
return
}