Skip to content

Commit

Permalink
feat: supports router map
Browse files Browse the repository at this point in the history
  • Loading branch information
kk0829 committed Apr 24, 2023
1 parent 2ec9542 commit ebb5763
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 74 deletions.
32 changes: 16 additions & 16 deletions group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ func TestGroup_AddRoute(t *testing.T) {
group := app.Group("/prefix")
handlers := []HandlerFunc{func(c *Context) {}}
group.AddRoute(http.MethodGet, "/path", handlers)
root := app.router.roots[http.MethodGet]
root := app.router.Roots[http.MethodGet]

route := root.children["prefix"].children["path"]
route := root.Children["prefix"].Children["path"]
if reflect.ValueOf(route.handlers[0]) != reflect.ValueOf(handlers[0]) {
t.Errorf("Expected handlers to be '%v', but got '%v'", route.handlers[0], handlers[0])
}
Expand Down Expand Up @@ -131,9 +131,9 @@ func TestGroup_Get(t *testing.T) {
group := app.Group("/prefix")
handlers := []HandlerFunc{func(c *Context) {}}
group.Get("/path", handlers...)
root := app.router.roots[http.MethodGet]
root := app.router.Roots[http.MethodGet]

route := root.children["prefix"].children["path"]
route := root.Children["prefix"].Children["path"]
if reflect.ValueOf(route.handlers[0]) != reflect.ValueOf(handlers[0]) {
t.Errorf("Expected handlers to be '%v', but got '%v'", route.handlers[0], handlers[0])
}
Expand All @@ -144,9 +144,9 @@ func TestGroup_Post(t *testing.T) {
group := app.Group("/prefix")
handlers := []HandlerFunc{func(c *Context) {}}
group.Post("/path", handlers...)
root := app.router.roots[http.MethodPost]
root := app.router.Roots[http.MethodPost]

route := root.children["prefix"].children["path"]
route := root.Children["prefix"].Children["path"]
if reflect.ValueOf(route.handlers[0]) != reflect.ValueOf(handlers[0]) {
t.Errorf("Expected handlers to be '%v', but got '%v'", route.handlers[0], handlers[0])
}
Expand All @@ -157,9 +157,9 @@ func TestGroup_Put(t *testing.T) {
group := app.Group("/prefix")
handlers := []HandlerFunc{func(c *Context) {}}
group.Put("/path", handlers...)
root := app.router.roots[http.MethodPut]
root := app.router.Roots[http.MethodPut]

route := root.children["prefix"].children["path"]
route := root.Children["prefix"].Children["path"]
if reflect.ValueOf(route.handlers[0]) != reflect.ValueOf(handlers[0]) {
t.Errorf("Expected handlers to be '%v', but got '%v'", route.handlers[0], handlers[0])
}
Expand All @@ -170,9 +170,9 @@ func TestGroup_Delete(t *testing.T) {
group := app.Group("/prefix")
handlers := []HandlerFunc{func(c *Context) {}}
group.Delete("/path", handlers...)
root := app.router.roots[http.MethodDelete]
root := app.router.Roots[http.MethodDelete]

route := root.children["prefix"].children["path"]
route := root.Children["prefix"].Children["path"]
if reflect.ValueOf(route.handlers[0]) != reflect.ValueOf(handlers[0]) {
t.Errorf("Expected handlers to be '%v', but got '%v'", route.handlers[0], handlers[0])
}
Expand All @@ -183,9 +183,9 @@ func TestGroup_Head(t *testing.T) {
group := app.Group("/prefix")
handlers := []HandlerFunc{func(c *Context) {}}
group.Head("/path", handlers...)
root := app.router.roots[http.MethodHead]
root := app.router.Roots[http.MethodHead]

route := root.children["prefix"].children["path"]
route := root.Children["prefix"].Children["path"]
if reflect.ValueOf(route.handlers[0]) != reflect.ValueOf(handlers[0]) {
t.Errorf("Expected handlers to be '%v', but got '%v'", route.handlers[0], handlers[0])
}
Expand All @@ -196,9 +196,9 @@ func TestGroup_Patch(t *testing.T) {
group := app.Group("/prefix")
handlers := []HandlerFunc{func(c *Context) {}}
group.Patch("/path", handlers...)
root := app.router.roots[http.MethodPatch]
root := app.router.Roots[http.MethodPatch]

route := root.children["prefix"].children["path"]
route := root.Children["prefix"].Children["path"]
if reflect.ValueOf(route.handlers[0]) != reflect.ValueOf(handlers[0]) {
t.Errorf("Expected handlers to be '%v', but got '%v'", route.handlers[0], handlers[0])
}
Expand All @@ -209,9 +209,9 @@ func TestGroup_Options(t *testing.T) {
group := app.Group("/prefix")
handlers := []HandlerFunc{func(c *Context) {}}
group.Options("/path", handlers...)
root := app.router.roots[http.MethodOptions]
root := app.router.Roots[http.MethodOptions]

route := root.children["prefix"].children["path"]
route := root.Children["prefix"].Children["path"]
if reflect.ValueOf(route.handlers[0]) != reflect.ValueOf(handlers[0]) {
t.Errorf("Expected handlers to be '%v', but got '%v'", route.handlers[0], handlers[0])
}
Expand Down
8 changes: 8 additions & 0 deletions lightning.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type Config struct {
JSONEncoder JSONMarshal
JSONDecoder JSONUnmarshal
NotFoundHandler HandlerFunc // Handler function for 404 Not Found error
EnableDebug bool
}

func (c *Config) merge(configs ...*Config) *Config {
Expand Down Expand Up @@ -58,6 +59,7 @@ func defaultConfig() *Config {
JSONEncoder: json.Marshal,
JSONDecoder: json.Unmarshal,
NotFoundHandler: defaultNotFound,
EnableDebug: true,
}
}

Expand All @@ -73,6 +75,12 @@ func NewApp(c ...*Config) *Application {
Logger: logger,
}

if app.Config.EnableDebug {
app.Get("/__debug__/router-map", func(ctx *Context) {
ctx.JSON(200, app.router.Roots)
})
}

return app
}

Expand Down
70 changes: 35 additions & 35 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,33 @@ import (

// trieNode represents a node in the trie data structure used by the router.
type trieNode struct {
children map[string]*trieNode // A map of child nodes keyed by their string values
isEnd bool // boolean flag indicating whether the node marks the end of a route
Children map[string]*trieNode `json:"children"` // A map of child nodes keyed by their string values
IsEnd bool `json:"isEnd"` // boolean flag indicating whether the node marks the end of a route
handlers []HandlerFunc // `HandlerFunc` functions that handles requests for the node's route
params map[string]int // a map of parameter names and their corresponding indices in the route pattern
wildcard string // a string representing the name of the wildcard parameter in the route pattern (if any)
Params map[string]int `json:"params"` // a map of parameter names and their corresponding indices in the route pattern
Wildcard string `json:"wildcard"` // a string representing the name of the wildcard parameter in the route pattern (if any)
}

// router represents the HTTP router.
type router struct {
roots map[string]*trieNode
Roots map[string]*trieNode `json:"roots"`
}

// newTrieNode creates a new instance of the `trieNode` struct with default values.
func newTrieNode() *trieNode {
return &trieNode{
children: make(map[string]*trieNode),
isEnd: false,
Children: make(map[string]*trieNode),
IsEnd: false,
handlers: make([]HandlerFunc, 0),
params: make(map[string]int),
wildcard: "",
Params: make(map[string]int),
Wildcard: "",
}
}

// newRouter creates a new instance of the `router` struct with an empty `roots` map.
func newRouter() *router {
return &router{
roots: make(map[string]*trieNode),
Roots: make(map[string]*trieNode),
}
}

Expand All @@ -42,10 +42,10 @@ func (r *router) addRoute(method string, pattern string, handlers []HandlerFunc)
if !isValidHTTPMethod(method) {
panic(fmt.Sprintf("method `%s` is not a standard HTTP method", method))
}
root, ok := r.roots[method]
root, ok := r.Roots[method]
if !ok {
root = newTrieNode()
r.roots[method] = root
r.Roots[method] = root
}

params := make(map[string]int)
Expand All @@ -55,36 +55,36 @@ func (r *router) addRoute(method string, pattern string, handlers []HandlerFunc)
// parameter
name := part[1:]
params[name] = i
if root.children[":"] == nil {
root.children[":"] = newTrieNode()
if root.Children[":"] == nil {
root.Children[":"] = newTrieNode()
}
root = root.children[":"]
root = root.Children[":"]
} else if part[0] == '*' {
// wildcard
name := part[1:]
if root.children["*"] == nil {
root.children["*"] = newTrieNode()
if root.Children["*"] == nil {
root.Children["*"] = newTrieNode()
}
root = root.children["*"]
root.wildcard = name
root = root.Children["*"]
root.Wildcard = name
break
} else {
// static
if root.children[part] == nil {
root.children[part] = newTrieNode()
if root.Children[part] == nil {
root.Children[part] = newTrieNode()
}
root = root.children[part]
root = root.Children[part]
}
}

root.isEnd = true // mark the end of the route
root.IsEnd = true // mark the end of the route
root.handlers = handlers // set the handlers for the route
root.params = params // set the parameters for the route
root.Params = params // set the parameters for the route
}

// findRoute is used to find the appropriate handler function for a given HTTP request method and URL pattern.
func (r *router) findRoute(method string, pattern string) ([]HandlerFunc, map[string]string) {
root, ok := r.roots[method]
root, ok := r.Roots[method]
if !ok {
return nil, nil
}
Expand All @@ -93,27 +93,27 @@ func (r *router) findRoute(method string, pattern string) ([]HandlerFunc, map[st

parts := parsePattern(pattern)
for i, part := range parts {
if root.children[part] != nil {
root = root.children[part]
} else if root.children[":"] != nil {
root = root.children[":"]
if root.Children[part] != nil {
root = root.Children[part]
} else if root.Children[":"] != nil {
root = root.Children[":"]
values[i] = part
} else if root.children["*"] != nil {
root = root.children["*"]
if root.wildcard != "" {
params[root.wildcard] = strings.Join(parts[i:], "/")
} else if root.Children["*"] != nil {
root = root.Children["*"]
if root.Wildcard != "" {
params[root.Wildcard] = strings.Join(parts[i:], "/")
}
break
} else {
return nil, nil
}
}

if !root.isEnd {
if !root.IsEnd {
return nil, nil
}

for name, index := range root.params {
for name, index := range root.Params {
params[name] = values[index]
}

Expand Down
46 changes: 23 additions & 23 deletions router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func TestNewRouter(t *testing.T) {
t.Errorf("newRouter returned nil")
}

if len(router.roots) != 0 {
if len(router.Roots) != 0 {
t.Errorf("newRouter did not initialize roots map correctly")
}
}
Expand All @@ -25,20 +25,20 @@ func TestNewTrieNode(t *testing.T) {
t.Error("Failed to create a new trieNode instance")
}

if node.isEnd != false {
t.Errorf("Expected isEnd to be false, but got %v", node.isEnd)
if node.IsEnd != false {
t.Errorf("Expected isEnd to be false, but got %v", node.IsEnd)
}

if len(node.handlers) != 0 {
t.Errorf("newTrieNode did not initialize handlers correctly")
}

if node.wildcard != "" {
t.Errorf("Expected wildcard to be empty, but got %v", node.wildcard)
if node.Wildcard != "" {
t.Errorf("Expected wildcard to be empty, but got %v", node.Wildcard)
}

if len(node.params) != 0 {
t.Errorf("Expected paramsMap to be empty, but got %v", node.params)
if len(node.Params) != 0 {
t.Errorf("Expected paramsMap to be empty, but got %v", node.Params)
}
}

Expand All @@ -51,21 +51,21 @@ func TestAddRouteStaticPatternValidHandler(t *testing.T) {
router.addRoute(method, pattern, handlers)

// Assert that the route was added correctly.
root := router.roots[method]
node, ok := root.children["home"]
root := router.Roots[method]
node, ok := root.Children["home"]
if !ok {
t.Errorf("expected route to be added, but wasn't")
}
if node == nil {
t.Errorf("expected a non-nil node, but got nil")
}
if !node.isEnd {
if !node.IsEnd {
t.Errorf("expected node to be an end node, but wasn't")
}
if len(node.handlers) == 0 {
t.Errorf("expected node to have a non-nil handler, but got nil")
}
if node.params == nil {
if node.Params == nil {
t.Errorf("expected node to have non-nil paramsMap, but got nil")
}
}
Expand All @@ -79,19 +79,19 @@ func TestAddRouteParameterizedPatternValidHandler(t *testing.T) {
router.addRoute(method, pattern, handlers)

// Assert that the route was added correctly.
root := router.roots[method]
node, ok := root.children["users"].children[":"]
root := router.Roots[method]
node, ok := root.Children["users"].Children[":"]
if !ok {
t.Errorf("Expected the route to be added, but it wasn't")
}
if node == nil {
t.Errorf("Expected a non-nil node, but got nil")
}
if node.params == nil {
if node.Params == nil {
t.Errorf("Expected non-nil paramsMap, but got nil")
}
if node.params["id"] != 1 {
t.Errorf("Expected 1 parameter, but got %d", node.params["id"])
if node.Params["id"] != 1 {
t.Errorf("Expected 1 parameter, but got %d", node.Params["id"])
}
}

Expand All @@ -104,26 +104,26 @@ func TestAddRouteWildcardPatternValidHandler(t *testing.T) {
router.addRoute(method, pattern, handlers)

// Assert that the route was added correctly.
root := router.roots[method]
node, ok := root.children["users"]
root := router.Roots[method]
node, ok := root.Children["users"]
if !ok {
t.Errorf("Expected the route to be added, but it wasn't")
}
node, ok = node.children["*"]
node, ok = node.Children["*"]
if node == nil {
t.Errorf("Expected a non-nil node, but got nil")
}
if !node.isEnd {
if !node.IsEnd {
t.Errorf("Expected node to be an end node, but wasn't")
}
if len(node.handlers) == 0 {
t.Errorf("Expected node to have a non-nil handler, but got nil")
}
if node.params == nil {
if node.Params == nil {
t.Errorf("Expected node to have non-nil paramsMap, but got nil")
}
if node.wildcard != "name" {
t.Errorf("Expected node to have wildcard 'name', but got '%s'", node.wildcard)
if node.Wildcard != "name" {
t.Errorf("Expected node to have wildcard 'name', but got '%s'", node.Wildcard)
}
}

Expand Down

0 comments on commit ebb5763

Please sign in to comment.