Skip to content

Commit 58f35f4

Browse files
authored
feat: added route name (#57)
1 parent d528573 commit 58f35f4

File tree

7 files changed

+58
-20
lines changed

7 files changed

+58
-20
lines changed

context.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ const contentTypeHeader string = "Content-Type"
1212
// Context is the context of current HTTP request.
1313
// It holds data related to current HTTP request.
1414
type Context struct {
15-
request *http.Request
16-
response ResponseWriter
17-
params Params
18-
storage Map
19-
kid *Kid
20-
lock sync.Mutex
15+
request *http.Request
16+
response ResponseWriter
17+
params Params
18+
storage Map
19+
kid *Kid
20+
lock sync.Mutex
21+
routeName string
2122
}
2223

2324
// newContext returns a new empty context.
@@ -32,13 +33,19 @@ func (c *Context) reset(request *http.Request, response http.ResponseWriter) {
3233
c.response = newResponse(response)
3334
c.storage = make(Map)
3435
c.params = make(Params)
36+
c.routeName = ""
3537
}
3638

3739
// setParams sets request's path parameters.
3840
func (c *Context) setParams(params Params) {
3941
c.params = params
4042
}
4143

44+
// setRouteName sets the route name.
45+
func (c *Context) setRouteName(name string) {
46+
c.routeName = name
47+
}
48+
4249
// Request returns plain request of current HTTP request.
4350
func (c *Context) Request() *http.Request {
4451
return c.request
@@ -68,6 +75,12 @@ func (c *Context) Path() string {
6875
return u.Path
6976
}
7077

78+
// Route returns current request's route name.
79+
// It's the user entered path, e.g. /greet/{name}.
80+
func (c *Context) Route() string {
81+
return c.routeName
82+
}
83+
7184
// Method returns request method.
7285
func (c *Context) Method() string {
7386
return c.request.Method
@@ -251,10 +264,11 @@ func (c *Context) Get(key string) (any, bool) {
251264
// Writes to the response of a cloned context will panic.
252265
func (c *Context) Clone() *Context {
253266
ctx := Context{
254-
request: c.request.Clone(context.Background()),
255-
response: c.response.(*response).clone(),
256-
kid: c.kid,
257-
lock: sync.Mutex{},
267+
request: c.request.Clone(context.Background()),
268+
response: c.response.(*response).clone(),
269+
kid: c.kid,
270+
lock: sync.Mutex{},
271+
routeName: c.routeName,
258272
}
259273

260274
// Copy path params.

context_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,3 +592,11 @@ func TestContext_Clone(t *testing.T) {
592592
clonedCtx.Response().Status()
593593
})
594594
}
595+
596+
func TestContext_Route(t *testing.T) {
597+
ctx := newContext(New())
598+
599+
ctx.setRouteName("route_name")
600+
601+
assert.Equal(t, "route_name", ctx.Route())
602+
}

kid.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ type (
4343
)
4444

4545
// Version of Kid.
46-
const Version string = "v0.3.0"
46+
const Version string = "v0.4.0"
4747

4848
// allMethods is a list of all HTTP methods.
4949
var allMethods = []string{
@@ -230,11 +230,14 @@ func (k *Kid) ServeHTTP(w http.ResponseWriter, r *http.Request) {
230230

231231
if err == errNotFound {
232232
handler = k.applyMiddlewaresToHandler(k.notFoundHandler, k.middlewares...)
233+
c.setRouteName("Not Found")
233234
} else if err == errMethodNotAllowed {
234235
handler = k.applyMiddlewaresToHandler(k.methodNotAllowedHandler, k.middlewares...)
236+
c.setRouteName("Method Not Allowed")
235237
} else {
236238
handler = k.applyMiddlewaresToHandler(route.handler, route.middlewares...)
237239
handler = k.applyMiddlewaresToHandler(handler, k.middlewares...)
240+
c.setRouteName(route.name)
238241
}
239242

240243
handler(c)

middlewares/logger.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,16 @@ func NewLoggerWithConfig(cfg LoggerConfig) kid.MiddlewareFunc {
9898
next(c)
9999

100100
end := time.Now()
101-
duration := end.Sub(start)
101+
elapsed := end.Sub(start)
102102

103103
status := c.Response().Status()
104104

105105
attrs := []slog.Attr{
106106
slog.Time("time", end),
107-
slog.Duration("latency_ns", duration),
108-
slog.String("latency", duration.String()),
107+
slog.Int64("latency_ms", elapsed.Milliseconds()),
108+
slog.String("latency", elapsed.String()),
109109
slog.Int("status", status),
110+
slog.String("route", c.Route()),
110111
slog.String("path", c.Path()),
111112
slog.String("method", c.Method()),
112113
slog.String("user_agent", c.GetRequestHeader("User-Agent")),

middlewares/logger_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ import (
1919
type logRecord struct {
2020
Msg string `json:"msg"`
2121
Time time.Time `json:"time"`
22-
LatenyNS int64 `json:"latency_ns"`
22+
LatenyMS int64 `json:"latency_ms"`
2323
Latency string `json:"latency"`
2424
Status int `json:"status"`
25+
Route string `json:"route"`
2526
Path string `json:"path"`
2627
Method string `json:"method"`
2728
UserAgent string `json:"user_agent"`
@@ -119,11 +120,12 @@ func TestNewLoggerWithConfig(t *testing.T) {
119120

120121
assert.Equal(t, testCase.status, logRecord.Status)
121122
assert.Equal(t, testCase.path, logRecord.Path)
123+
assert.Equal(t, testCase.path, logRecord.Route)
122124
assert.Equal(t, http.MethodGet, logRecord.Method)
123125
assert.Equal(t, "Go Test", logRecord.UserAgent)
124126
assert.NotZero(t, logRecord.Time)
125127
assert.NotEmpty(t, logRecord.Latency)
126-
assert.NotEmpty(t, logRecord.LatenyNS)
128+
assert.NotEmpty(t, logRecord.LatenyMS)
127129
assert.Equal(t, testCase.msg, logRecord.Msg)
128130
})
129131
}

tree.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,14 @@ const (
2424
type (
2525
// handlerMiddleware zips a handler and its middlewares to each other.
2626
handlerMiddleware struct {
27-
handler HandlerFunc
27+
// handler is the route request handler.
28+
handler HandlerFunc
29+
30+
// middlewares is route middlewares.
2831
middlewares []MiddlewareFunc
32+
33+
// name is route name.
34+
name string
2935
}
3036

3137
// Tree is a tree used for routing.
@@ -112,11 +118,12 @@ func (t *Tree) insertNode(path string, methods []string, middlewares []Middlewar
112118
currNode = child
113119
}
114120
} else { // Only for the last iteration of the for loop.
121+
hm := handlerMiddleware{handler: handler, middlewares: middlewares, name: path}
115122
if child := currNode.getChild(node.label, node.isParam, node.isStar); child == nil {
116-
node.addHanlder(methods, handlerMiddleware{handler: handler, middlewares: middlewares})
123+
node.addHanlder(methods, hm)
117124
currNode.addChild(&node)
118125
} else {
119-
child.addHanlder(methods, handlerMiddleware{handler: handler, middlewares: middlewares})
126+
child.addHanlder(methods, hm)
120127
}
121128
}
122129
}
@@ -185,6 +192,7 @@ func (n *Node) addHanlder(methods []string, hm handlerMiddleware) {
185192
}
186193
}
187194

195+
// setLabel sets the node's appropriate label.
188196
func (n *Node) setLabel(label string) {
189197
n.label = label
190198
if n.isParam {

tree_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func TestNode_addHanlder(t *testing.T) {
7171

7272
assert.PanicsWithValue(
7373
t,
74-
"handler is already registered for method GET and node &{id:0 label: children:[] isParam:false isStar:false handlerMap:map[GET:{handler:<nil> middlewares:[]} POST:{handler:<nil> middlewares:[]}]}.",
74+
"handler is already registered for method GET and node &{id:0 label: children:[] isParam:false isStar:false handlerMap:map[GET:{handler:<nil> middlewares:[] name:} POST:{handler:<nil> middlewares:[] name:}]}.",
7575
func() {
7676
node.addHanlder([]string{http.MethodGet, http.MethodPost}, handlerMiddleware{})
7777
},
@@ -123,6 +123,7 @@ func TestTree_insertNode(t *testing.T) {
123123
assert.True(t, ok)
124124
assert.True(t, funcsAreEqual(hm.handler, testHandlerFunc))
125125
assert.Nil(t, hm.middlewares)
126+
assert.Equal(t, "/test/path", hm.name)
126127

127128
tree.insertNode("/test", []string{http.MethodPost}, []MiddlewareFunc{testMiddlewareFunc}, testHandlerFunc)
128129

@@ -140,6 +141,7 @@ func TestTree_insertNode(t *testing.T) {
140141
assert.True(t, ok)
141142
assert.True(t, funcsAreEqual(hm.handler, testHandlerFunc))
142143
assert.Len(t, hm.middlewares, 1)
144+
assert.Equal(t, "/test", hm.name)
143145
}
144146

145147
func TestNode_insert_Panics(t *testing.T) {

0 commit comments

Comments
 (0)