-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmux.go
168 lines (146 loc) · 4.79 KB
/
mux.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
package nchi
import (
"net/http"
"github.com/muir/nject"
"github.com/pkg/errors"
"github.com/julienschmidt/httprouter"
)
type Params = httprouter.Params
// Endpoint is a type that handlers can accepte as an input. It will be the
// combined URL path without path variables substituted. If you have
//
// mux.Get("/thing/:thingID", handler)
//
// and handler takes an nchi.Endpoint argument, and there is a request for
// http://example.com/thing/3802, then the nchi.Endpoint will be "/thing/:thingID".
type Endpoint string
type Mux struct {
providers *nject.Collection // partial set
routes []*Mux
path string // a fragment
method string // set for endpoints only
router *httprouter.Router // only set at top-most
group bool
options []Option
special *special
}
func (mux *Mux) add(n *Mux) *Mux {
mux.routes = append(mux.routes, n)
if !n.group {
n.providers = mux.providers.Append(n.path, n.providers)
}
return n
}
// With is just like Use except that it returns a new Mux instead of
// modifying the current one
func (mux *Mux) With(providers ...interface{}) *Mux {
return mux.add(&Mux{
providers: nject.Sequence(mux.path, translateMiddleware(providers)...),
})
}
// Route establishes a new Mux at a new path (combined with the
// current path context).
func (mux *Mux) Route(path string, f func(mux *Mux)) {
f(mux.add(&Mux{
path: path,
providers: nject.Sequence(mux.path),
}))
}
// Group establishes a new Mux at the current path but does
// not inherit any middlewhere.
func (mux *Mux) Group(f func(mux *Mux)) {
f(mux.add(&Mux{
group: true,
providers: nject.Sequence(mux.path),
}))
}
// Method registers an endpoint handler at the new path (combined with
// the current path) using a combination of inherited middleware and
// the providers here.
func (mux *Mux) Method(method string, path string, providers ...interface{}) {
mux.add(&Mux{
providers: nject.Sequence(method+" "+path, translateMiddleware(providers)...),
method: method,
path: path,
})
}
func (mux *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if mux.router == nil {
err := mux.Bind()
if err != nil {
panic(err.Error())
}
}
mux.router.ServeHTTP(w, r)
}
// Bind validates that the injection chains for all routes are valid.
// If any are not, an error is returned. If you do not call bind, and
// there are any invalid injection chains, then routes will panic when
// used.
func (mux *Mux) Bind() error {
router := httprouter.New()
for _, opt := range mux.options {
opt(&rtr{router})
}
err := mux.bind(router, "")
if err != nil {
return err
}
mux.router = router
return nil
}
func (mux *Mux) bind(router *httprouter.Router, path string) error {
combinedPath := path + mux.path
for _, route := range mux.routes {
err := route.bind(router, combinedPath)
if err != nil {
return err
}
}
providers := nject.Sequence(path,
Endpoint(combinedPath),
mux.providers,
)
if mux.special != nil {
return mux.bindSpecial(router, combinedPath, providers)
}
if mux.method == "" {
return nil
}
var handle httprouter.Handle
err := providers.Bind(&handle, nil)
if err != nil {
return errors.Wrapf(err, "bind router %s %s", mux.method, combinedPath)
}
router.Handle(mux.method, combinedPath, handle)
return nil
}
// Use adds additional http middleware (implementing the http.Handler interface)
// or nject-style providers to the current handler context. These middleware
// and providers will be injected into the handler chain for any downstream
// endpoints that are defined after the call to Use.
func (mux *Mux) Use(providers ...interface{}) {
n := "router"
if mux.path != "" {
n = mux.path
}
mux.providers = mux.providers.Append(n, translateMiddleware(providers)...)
}
// Get establish a route for HTTP GET requests
func (mux *Mux) Get(path string, providers ...interface{}) { mux.Method("GET", path, providers...) }
// Head establish a route for HTTP HEAD requests
func (mux *Mux) Head(path string, providers ...interface{}) { mux.Method("HEAD", path, providers...) }
// Post establish a route for HTTP POST requests
func (mux *Mux) Post(path string, providers ...interface{}) { mux.Method("POST", path, providers...) }
// Put establish a route for HTTP PUT requests
func (mux *Mux) Put(path string, providers ...interface{}) { mux.Method("PUT", path, providers...) }
// Patch establish a route for HTTP PATCH requests
func (mux *Mux) Patch(path string, providers ...interface{}) { mux.Method("PATCH", path, providers...) }
// Options establish a route for HTTP OPTIONS requests.
func (mux *Mux) Options(path string, providers ...interface{}) {
mux.Method("OPTIONS", path, providers...)
}
// Delete establish a route for HTTP DELETE requests.
func (mux *Mux) Delete(path string, providers ...interface{}) {
mux.Method("DELETE", path, providers...)
}