-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathgroup.go
More file actions
206 lines (181 loc) · 8.43 KB
/
Copy pathgroup.go
File metadata and controls
206 lines (181 loc) · 8.43 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
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: © 2015 LabStack LLC and Echo contributors
package echo
import (
"io/fs"
"net/http"
)
// Group is a set of sub-routes for a specified route. It can be used for inner
// routes that share a common middleware or functionality that should be separate
// from the parent echo instance while still inheriting from it.
type Group struct {
echo *Echo
prefix string
middleware []MiddlewareFunc
// noAutoRegisterRoutes is a flag that indicates whether Group should NOT register 404 routes automatically
// when there are middlewares registered with the group.
// Note: if you decide not to register 404 routes automatically, make sure to check if all your middlewares are executed
// as expected. For example - CORS middleware.
noAutoRegisterRoutes bool
}
// Use implements `Echo#Use()` for sub-routes within the Group.
//
// Important! Group middlewares are executed in case there was no exact route match as by default Group registers
// `/*` NotFound routes for itself. If this kind of behavior is not needed, then create an Echo instance with the ` noAutoRegisterRoutes `
// flag set to true. Example `echo.NewWithConfig(echo.Config{NoGroupAutoRegister404Routes: true})`.
func (g *Group) Use(middleware ...MiddlewareFunc) {
g.middleware = append(g.middleware, middleware...)
if len(g.middleware) == 0 {
return
}
if g.noAutoRegisterRoutes {
return
}
// group level middlewares are different from Echo `Pre` and `Use` middlewares (those are global). Group level middlewares
// are only executed if they are added to the Router with route.
// So we register catch all route (404 is a safe way to emulate route match) for this group and now during routing the
// Router would find route to match our request path and therefore guarantee the middleware(s) will get executed.
// Note: we use nil handler so Router would choose the default 404 handler. This may not work with custom routers.
g.RouteNotFound("", nil)
g.RouteNotFound("/*", nil)
}
// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group. Panics on error.
func (g *Group) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(http.MethodConnect, path, h, m...)
}
// DELETE implements `Echo#DELETE()` for sub-routes within the Group. Panics on error.
func (g *Group) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(http.MethodDelete, path, h, m...)
}
// GET implements `Echo#GET()` for sub-routes within the Group. Panics on error.
func (g *Group) GET(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(http.MethodGet, path, h, m...)
}
// HEAD implements `Echo#HEAD()` for sub-routes within the Group. Panics on error.
func (g *Group) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(http.MethodHead, path, h, m...)
}
// OPTIONS implements `Echo#OPTIONS()` for sub-routes within the Group. Panics on error.
func (g *Group) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(http.MethodOptions, path, h, m...)
}
// PATCH implements `Echo#PATCH()` for sub-routes within the Group. Panics on error.
func (g *Group) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(http.MethodPatch, path, h, m...)
}
// POST implements `Echo#POST()` for sub-routes within the Group. Panics on error.
func (g *Group) POST(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(http.MethodPost, path, h, m...)
}
// PUT implements `Echo#PUT()` for sub-routes within the Group. Panics on error.
func (g *Group) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(http.MethodPut, path, h, m...)
}
// QUERY implements `Echo#QUERY()` for sub-routes within the Group. Panics on error.
func (g *Group) QUERY(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(QUERY, path, h, m...)
}
// TRACE implements `Echo#TRACE()` for sub-routes within the Group. Panics on error.
func (g *Group) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(http.MethodTrace, path, h, m...)
}
// Any implements `Echo#Any()` for sub-routes within the Group. Panics on error.
func (g *Group) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) RouteInfo {
return g.Add(RouteAny, path, handler, middleware...)
}
// Match implements `Echo#Match()` for sub-routes within the Group. Panics on error.
func (g *Group) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) Routes {
errs := make([]error, 0)
ris := make(Routes, 0)
for _, m := range methods {
ri, err := g.AddRoute(Route{
Method: m,
Path: path,
Handler: handler,
Middlewares: middleware,
})
if err != nil {
errs = append(errs, err)
continue
}
ris = append(ris, ri)
}
if len(errs) > 0 {
panic(errs) // this is how `v4` handles errors. `v5` has methods to have panic-free usage
}
return ris
}
// Group creates a new sub-group with prefix and optional sub-group-level middleware.
//
// Important! Group middlewares are executed in case there was no exact route match as by default Group registers
// `/*` NotFound routes for itself. If this kind of behavior is not needed, then create an Echo instance with the ` noAutoRegisterRoutes `
// flag set to true. Example `echo.NewWithConfig(echo.Config{NoGroupAutoRegister404Routes: true})`.
func (g *Group) Group(prefix string, middleware ...MiddlewareFunc) (sg *Group) {
m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
m = append(m, g.middleware...)
m = append(m, middleware...)
sg = g.echo.Group(g.prefix+prefix, m...)
return
}
// Static implements `Echo#Static()` for sub-routes within the Group.
func (g *Group) Static(pathPrefix, fsRoot string, middleware ...MiddlewareFunc) RouteInfo {
subFs := MustSubFS(g.echo.Filesystem, fsRoot)
return g.StaticFS(pathPrefix, subFs, middleware...)
}
// StaticFS implements `Echo#StaticFS()` for sub-routes within the Group.
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
func (g *Group) StaticFS(pathPrefix string, filesystem fs.FS, middleware ...MiddlewareFunc) RouteInfo {
return g.Add(
http.MethodGet,
pathPrefix+"*",
StaticDirectoryHandler(filesystem, !g.echo.enablePathUnescapingStaticFiles),
middleware...,
)
}
// FileFS implements `Echo#FileFS()` for sub-routes within the Group.
//
// Avoid using the leading `/` slash as most of the Go standard library fs.FS implementations require relative paths for
// file operations.
func (g *Group) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) RouteInfo {
return g.GET(path, StaticFileHandler(file, filesystem), m...)
}
// File implements `Echo#File()` for sub-routes within the Group. Panics on error.
//
// Avoid using the leading `/` slash as most of the Go standard library fs.FS implementations require relative paths for
// file operations.
func (g *Group) File(path, file string, middleware ...MiddlewareFunc) RouteInfo {
handler := func(c *Context) error {
return c.File(file)
}
return g.Add(http.MethodGet, path, handler, middleware...)
}
// RouteNotFound implements `Echo#RouteNotFound()` for sub-routes within the Group.
//
// Example: `g.RouteNotFound("/*", func(c *echo.Context) error { return c.NoContent(http.StatusNotFound) })`
func (g *Group) RouteNotFound(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {
return g.Add(RouteNotFound, path, h, m...)
}
// Add implements `Echo#Add()` for sub-routes within the Group. Panics on error.
func (g *Group) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) RouteInfo {
ri, err := g.AddRoute(Route{
Method: method,
Path: path,
Handler: handler,
Middlewares: middleware,
})
if err != nil {
panic(err) // this is how `v4` handles errors. `v5` has methods to have panic-free usage
}
return ri
}
// AddRoute registers a new Routable with Router
func (g *Group) AddRoute(route Route) (RouteInfo, error) {
// Combine middleware into a new slice to avoid accidentally passing the same slice for
// multiple routes, which would lead to later add() calls overwriting the
// middleware from earlier calls.
groupRoute := route.WithPrefix(g.prefix, append([]MiddlewareFunc{}, g.middleware...))
return g.echo.add(groupRoute)
}