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
|
package mooh
import (
"regexp"
"strings"
"net/http"
)
type fn func(*Request) (Response, error)
type fns map[string]fn
type Route struct {
Path string
Executors fns
Components []string
RequiredNamedComponents map[string]bool
OptionalNamedComponents map[string]bool
Length int
LengthWithoutOptional int
}
type Match struct {
Path string
Route Route
Mapping map[string]string
Method string
}
var componentIsVariable = regexp.MustCompile("^:")
var componentsIsOptional = regexp.MustCompile("^?:")
var namedComponentsRegex = regexp.MustCompile("^:(.*)$")
func (self *Route) Match(request *http.Request) *Match {
methodMatch := false
for m, _ := range self.Executors {
if m == request.Method {
methodMatch = true
}
}
if methodMatch == false {
return nil
}
components := strings.Split(request.URL.Path, "/")
if len(components) < self.LengthWithoutOptional || len(components) > self.Length {
return nil
}
mapping := map[string]string{}
for i, c := range self.Components {
if componentsIsOptional.MatchString(c) {
break
}
p := components[i]
if componentIsVariable.MatchString(c) == true {
mapping[c] = p
} else {
if p != c {
return nil
}
}
}
return &Match{
Path: request.URL.Path,
Route: *self,
Method: request.Method,
Mapping: mapping,
}
}
func (self *Route) Execute(request *Request) (Response, error) {
code := self.Executors[request.Method]
return code(request)
}
func MakeRoute(path string, method string, code fn) Route {
components := []string{}
for _, c := range strings.Split(path, "/") {
components = append(components, c)
}
reqComponents, optComponents := getNamedComponents(components)
exec := fns{method: code}
route := Route{
Path: path,
Executors: exec,
Components: components,
RequiredNamedComponents: reqComponents,
OptionalNamedComponents: optComponents,
Length: len(components),
LengthWithoutOptional: len(components) - len(optComponents),
}
return route
}
func getNamedComponents(components []string) (map[string]bool, map[string]bool) {
reqComponents := map[string]bool{}
optComponents := map[string]bool{}
for _, c := range components {
if namedComponentsRegex.MatchString(c) == true {
reqComponents[c] = true
} else if componentsIsOptional.MatchString(c) == true {
optComponents[c] = true
}
}
return reqComponents, optComponents
}
|