This repository has been archived by the owner on Oct 7, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgonion.go
194 lines (165 loc) · 6 KB
/
gonion.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
186
187
188
189
190
191
192
193
194
package gonion
import (
"net/http"
"strings"
)
//Composer is the main API in gonion and is responsible for
//composing the middleware and routes of your application
type Composer struct {
start string
routeRegistry *routeRegistry
middlewareRegistry *middlewareRegistry
}
//New is a factory method for Composer
func New() *Composer {
routeRegistry := newRouteRegistry()
middlewareRegistry := newMiddlewareRegistry()
return &Composer{
start: "",
routeRegistry: routeRegistry,
middlewareRegistry: middlewareRegistry,
}
}
//Sub will allow you to specify middleware and routes that only
//apply for the specified path. This can be done recursively and
//at each level will inherit the previous path's middleware.
func (composer *Composer) Sub(pattern string, sub func(*Composer)) {
subComposer := &Composer{
start: composer.start + pattern,
routeRegistry: composer.routeRegistry,
middlewareRegistry: composer.middlewareRegistry,
}
sub(subComposer)
}
func (composer *Composer) addMiddleware(link ChainLink, routeFilter func(*RouteModel) bool) {
composer.middlewareRegistry.add(func(route *RouteModel) bool {
return (composer.start == "" || strings.HasPrefix(route.Pattern, composer.start)) && routeFilter(route)
}, link)
}
//Use is the entrypoint to adding middleware
func (composer *Composer) Use() *MiddlewareOptions {
return composer.useWhen(func(route *RouteModel) bool {
return true
})
}
func (composer *Composer) useWhen(routeFilter func(*RouteModel) bool) *MiddlewareOptions {
return &MiddlewareOptions{
composer: composer,
routeFilter: routeFilter,
}
}
//Get adds a route constrained to only 'GET' requests
func (composer *Composer) Get(pattern string, handler http.Handler) {
composer.Handle("GET", pattern, handler)
}
//Post adds a route constrained to only 'POST' requests
func (composer *Composer) Post(pattern string, handler http.Handler) {
composer.Handle("POST", pattern, handler)
}
//Put adds a route constrained to only 'PUT' requests
func (composer *Composer) Put(pattern string, handler http.Handler) {
composer.Handle("PUT", pattern, handler)
}
//Patch adds a route constrained to only 'PATCH' requests
func (composer *Composer) Patch(pattern string, handler http.Handler) {
composer.Handle("PATCH", pattern, handler)
}
//Delete adds a route constrained to only 'DELETE' requests
func (composer *Composer) Delete(pattern string, handler http.Handler) {
composer.Handle("DELETE", pattern, handler)
}
//Handle adds a route for the specified method and pattern
func (composer *Composer) Handle(method string, pattern string, handler http.Handler) {
composer.routeRegistry.addRoute(method, composer.start+pattern, handler)
}
//RouteConstraint is how middleware is constrained after calling Only()
type RouteConstraint struct {
composer *Composer
routeFilter func(*RouteModel) bool
}
//Only allows you to constrain middleware for only certain types of routes.
//This isn't just a runtime filter, it excludes it from the chain while building the routes
//on startup.
func (composer *Composer) Only() *RouteConstraint {
return &RouteConstraint{
composer: composer,
routeFilter: nil,
}
}
//WhenRouteMatches is a constraint that gives you all the route information to filter upon.
func (rc *RouteConstraint) WhenRouteMatches(routeFilter func(*RouteModel) bool) *RouteConstraint {
rc.routeFilter = routeFilter
return rc
}
//When is a constraint that gives you the option to only apply upon a condition being true
func (rc *RouteConstraint) When(condition func() bool) *RouteConstraint {
return rc.WhenRouteMatches(func(r *RouteModel) bool {
return condition()
})
}
//Get constrains the middleware to only apply for 'GET' requests
func (rc *RouteConstraint) Get() *RouteConstraint {
return rc.methodConstraint("GET")
}
//Post constrains the middleware to only apply for 'POST' requests
func (rc *RouteConstraint) Post() *RouteConstraint {
return rc.methodConstraint("POST")
}
//Put constrains the middleware to only apply for 'PUT' requests
func (rc *RouteConstraint) Put() *RouteConstraint {
return rc.methodConstraint("PUT")
}
//Patch constrains the middleware to only apply for 'PATCH' requests
func (rc *RouteConstraint) Patch() *RouteConstraint {
return rc.methodConstraint("PATCH")
}
//Delete constrains the middleware to only apply for 'DELETE' requests
func (rc *RouteConstraint) Delete() *RouteConstraint {
return rc.methodConstraint("DELETE")
}
func (rc *RouteConstraint) methodConstraint(method string) *RouteConstraint {
return rc.WhenRouteMatches(func(route *RouteModel) bool {
return route.Method == method
})
}
//Use is the entrypoint to defining your middleware, but only for the current
//defined route constraint
func (rc *RouteConstraint) Use() *MiddlewareOptions {
return rc.composer.useWhen(rc.routeFilter)
}
//Routes is the array of routes and built middleware. This will be what's returned
//after calling BuildRoutes
type Routes []*Route
//Route is the handler and route information after calling BuildRoutes. Handler
//is the entire chain of route handler and middleware.
type Route struct {
Method string
Pattern string
Handler http.Handler
}
//BuildRoutes returns routes with their corresponding handler chain.
//This is typically what you will call before delegating to the router
//you have chosen for your application.
func (composer *Composer) BuildRoutes() Routes {
routes := make(Routes, 0, 10)
for i := len(composer.routeRegistry.routes) - 1; i >= 0; i-- {
route := composer.routeRegistry.routes[i]
middleware := composer.middlewareRegistry.middlewareFor(route)
handler := build(route.Handler, middleware)
builtRoute := &Route{
Method: route.Method,
Pattern: route.Pattern,
Handler: handler,
}
routes = append(routes, builtRoute)
}
return routes
}
//EachRoute is a convenience method for BuildRoutes that you can
//pass a func to be called on each route from BuildRoutes.
func (composer *Composer) EachRoute(router func(*Route)) {
routes := composer.BuildRoutes()
for _, route := range routes {
router(route)
}
}