package mooh import ( "net/http" "regexp" "strings" ) 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("^:(.*)$") var convertComponent = regexp.MustCompile("^\\??:(.*)$") func (self *Route) convertComponentName(name string) string { newName := convertComponent.FindStringSubmatch(name) return newName[1] } 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[self.convertComponentName(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 }