-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrouter.go
106 lines (88 loc) · 3.15 KB
/
router.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
package temaki
import (
"context"
"fmt"
"net/http"
"strings"
)
type Router struct {
Routes *[]Route
Middlewares *[]Middleware
}
func NewRouter() *Router {
return &Router{&[]Route{}, &[]Middleware{}}
}
func (router *Router) UseMiddleware(middleware ...Middleware) *Router {
*router.Middlewares = append(*router.Middlewares, middleware...)
return router
}
func (router *Router) GET(pattern string, handlerFunc http.HandlerFunc) *Router {
*router.Routes = append(*router.Routes, NewRoute("GET", pattern, handlerFunc))
return router
}
func (router *Router) POST(pattern string, handlerFunc http.HandlerFunc) *Router {
*router.Routes = append(*router.Routes, NewRoute("OPTIONS", pattern, handlerFunc))
*router.Routes = append(*router.Routes, NewRoute("POST", pattern, handlerFunc))
return router
}
func (router *Router) PUT(pattern string, handlerFunc http.HandlerFunc) *Router {
*router.Routes = append(*router.Routes, NewRoute("OPTIONS", pattern, handlerFunc))
*router.Routes = append(*router.Routes, NewRoute("PUT", pattern, handlerFunc))
return router
}
func (router *Router) PATCH(pattern string, handlerFunc http.HandlerFunc) *Router {
*router.Routes = append(*router.Routes, NewRoute("OPTIONS", pattern, handlerFunc))
*router.Routes = append(*router.Routes, NewRoute("PATCH", pattern, handlerFunc))
return router
}
func (router *Router) DELETE(pattern string, handlerFunc http.HandlerFunc) *Router {
*router.Routes = append(*router.Routes, NewRoute("OPTIONS", pattern, handlerFunc))
*router.Routes = append(*router.Routes, NewRoute("DELETE", pattern, handlerFunc))
return router
}
func (router *Router) OPTIONS(pattern string, handlerFunc http.HandlerFunc) *Router {
*router.Routes = append(*router.Routes, NewRoute("OPTIONS", pattern, handlerFunc))
return router
}
func (router *Router) HEAD(pattern string, handlerFunc http.HandlerFunc) *Router {
*router.Routes = append(*router.Routes, NewRoute("HEAD", pattern, handlerFunc))
return router
}
func (router *Router) DispatcherHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var allow []string
for _, route := range *router.Routes {
matches := route.regex.FindStringSubmatch(r.URL.Path)
if len(matches) > 0 {
if r.Method != route.method {
allow = append(allow, route.method)
continue
}
r = enrichRequestContext(r, ctxKey{}, matches[1:])
r = enrichRequestContext(r, "pathParamsMap", route.pathParams)
route.handler(w, r)
return
}
}
if len(allow) > 0 {
w.Header().Set("Allow", strings.Join(allow, ", "))
http.Error(w, "405 method not allowed", http.StatusMethodNotAllowed)
return
}
http.NotFound(w, r)
}
}
func (router *Router) Serve() http.Handler {
var finalHandler http.Handler = http.HandlerFunc(router.DispatcherHandler())
for _, middleware := range *router.Middlewares {
finalHandler = middleware(finalHandler)
}
return finalHandler
}
func (router *Router) Start(port int) error {
return http.ListenAndServe(fmt.Sprintf(":%d", port), router.Serve())
}
func enrichRequestContext(r *http.Request, key, val interface{}) *http.Request {
ctx := context.WithValue(r.Context(), key, val)
return r.WithContext(ctx)
}