-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrouter.go
115 lines (103 loc) · 2.64 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
107
108
109
110
111
112
113
114
115
package router
import (
"github.com/aws/aws-lambda-go/events"
"regexp"
"strings"
)
type Request events.APIGatewayProxyRequest
type Response events.APIGatewayProxyResponse
type Route struct {
Pattern string
Handler func(Request, map[string]string) (Response, error)
}
type Router struct {
GETs []Route
POSTs []Route
DELETEs []Route
}
func (r *Router) DelegateRequest(request Request) (Response, error) {
var routes []Route
switch request.HTTPMethod {
case "GET":
routes = r.GETs
case "POST":
routes = r.POSTs
case "DELETE":
routes = r.DELETEs
default:
routes = r.GETs
}
for _, route := range routes {
params, ok := matchRoute(route.Pattern, request.Path)
if ok {
return route.Handler(request, params)
}
}
return Response{StatusCode: 404}, nil
}
func (r *Router) GET(path string, f func(Request, map[string]string) (Response, error)) {
r.GETs = append(r.GETs, Route{
Pattern: path,
Handler: f,
})
}
func (r *Router) POST(path string, f func(Request, map[string]string) (Response, error)) {
r.POSTs = append(r.POSTs, Route{
Pattern: path,
Handler: f,
})
}
func (r *Router) DELETE(path string, f func(Request, map[string]string) (Response, error)) {
r.DELETEs = append(r.DELETEs, Route{
Pattern: path,
Handler: f,
})
}
func (r *Router) dumpRoutes() map[string][]Route {
return map[string][]Route{
"GET": r.GETs,
"POST": r.POSTs,
}
}
func matchRoute(route string, path string) (map[string]string, bool) {
pattern := regexp.MustCompile(createPatternFromRoute(route))
matched := pattern.MatchString(path)
results := make(map[string]string)
if matched {
template := createTemplateFromRoute(route)
result := []byte{}
for _, submatches := range pattern.FindAllStringSubmatchIndex(path, -1) {
result = pattern.ExpandString(result, template, path, submatches)
}
for _, pair := range strings.Split(string(result), "\n") {
kv := strings.Split(pair, "=")
if len(kv) == 2 {
results[kv[0]] = kv[1]
}
}
}
return results, matched
}
func createPatternFromRoute(route string) string {
components := strings.Split(route, "/")
for i, component := range components {
if strings.HasPrefix(component, ":") {
name := component[1:]
regex := `(?P<` + name + `>\w+)`
components[i] = regex
}
}
return strings.Join(components, "/")
}
func createTemplateFromRoute(route string) string {
components := strings.Split(route, "/")
var template_items []string
for _, component := range components {
if strings.HasPrefix(component, ":") {
name := component[1:]
template_item := name + `=$` + name
template_items = append(template_items, template_item)
}
}
return strings.Join(template_items, "\n")
}