Skip to content

Commit 90f164f

Browse files
author
Sergio Andres Virviescas Santana
committed
Add optional path parameters
Squashed commit of the following: commit a0e345f2d1920b0be478d94ae56de21f446ec5bf Author: Sergio Andres Virviescas Santana <[email protected]> Date: Sun Jul 14 18:26:23 2019 +0200 Update README commit f48f81403503ecda5057745414c27ba844a5a2b1 Author: Sergio Andres Virviescas Santana <[email protected]> Date: Sun Jul 14 18:14:06 2019 +0200 Add test commit 3a4aeb01482cbe79b5f95b09fca74ed194d309e7 Author: Sergio Andres Virviescas Santana <[email protected]> Date: Sun Jul 14 17:42:56 2019 +0200 Fixes commit 3ca5a4a5f158a716a9c99fc24d50d8e1688cd179 Author: Sergio Andres Virviescas Santana <[email protected]> Date: Sun Jul 14 11:31:43 2019 +0200 Add optional path arguments
1 parent dad1702 commit 90f164f

File tree

6 files changed

+74
-4
lines changed

6 files changed

+74
-4
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ Pattern: /user/:user
126126

127127
**Note:** Since this router has only explicit matches, you can not register static routes and parameters for the same path segment. For example you can not register the patterns `/user/new` and `/user/:user` for the same request method at the same time. The routing of different request methods is independent from each other.
128128

129+
#### Optional parameters
130+
If you need define an optional parameters, add `?` at the end of param name. `:name?`
131+
129132
### Catch-All parameters
130133

131134
The second type are *catch-all* parameters and have the form `*name`.

examples/basic/basic.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ func main() {
3636
r.GET("/", Index)
3737
r.GET("/hello/:name", Hello)
3838
r.GET("/multi/:name/:word", MultiParams)
39+
r.GET("/optional/:name?/:word?", MultiParams)
3940
r.GET("/ping", QueryArgs)
4041

4142
log.Fatal(fasthttp.ListenAndServe(":8080", r.Handler))

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module github.com/fasthttp/router
22

33
require (
4-
github.com/savsgio/gotils v0.0.0-20190409142739-e36d23089e10
4+
github.com/savsgio/gotils v0.0.0-20190714152828-365999d0a274
55
github.com/valyala/bytebufferpool v1.0.0
66
github.com/valyala/fasthttp v1.4.0
77
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ github.com/klauspost/compress v1.4.0 h1:8nsMz3tWa9SWWPL60G1V6CUsf4lLjWLTNEtibhe8
22
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
33
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e h1:+lIPJOWl+jSiJOc70QXJ07+2eg2Jy2EC7Mi11BWujeM=
44
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
5-
github.com/savsgio/gotils v0.0.0-20190409142739-e36d23089e10 h1:Rk4AHSMs6BX9Vb84H+SmYEA3X/VrtLV9qYSU/lc7xk4=
6-
github.com/savsgio/gotils v0.0.0-20190409142739-e36d23089e10/go.mod h1:w803/Fg1m0hrp1ZT9KNfQe4E4+WOMMFLcgzPvOcye10=
5+
github.com/savsgio/gotils v0.0.0-20190714152828-365999d0a274 h1:F52t1X2ziOrMcQMVHo8ZxwOrDTMAq6MrlKtL1Atu2wU=
6+
github.com/savsgio/gotils v0.0.0-20190714152828-365999d0a274/go.mod h1:w803/Fg1m0hrp1ZT9KNfQe4E4+WOMMFLcgzPvOcye10=
77
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
88
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
99
github.com/valyala/fasthttp v1.4.0 h1:PuaTGZIw3mjYhhhbVbCQp8aciRZN9YdoB7MGX9Ko76A=

router.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,36 @@ func (r *Router) DELETE(path string, handle fasthttp.RequestHandler) {
202202
r.Handle("DELETE", path, handle)
203203
}
204204

205+
// returns all possible paths when the original path has optional arguments
206+
func getOptionalPaths(path string) []string {
207+
paths := make([]string, 0)
208+
209+
index := 0
210+
newParam := false
211+
for i := 0; i < len(path); i++ {
212+
c := path[i]
213+
214+
if c == ':' {
215+
index = i
216+
newParam = true
217+
} else if i > 0 && newParam && c == '?' {
218+
p := strings.Replace(path[:index], "?", "", -1)
219+
if !gotils.StringSliceInclude(paths, p) {
220+
paths = append(paths, p)
221+
}
222+
223+
p = strings.Replace(path[:i], "?", "", -1) + "/"
224+
if !gotils.StringSliceInclude(paths, p) {
225+
paths = append(paths, p)
226+
}
227+
228+
newParam = false
229+
}
230+
}
231+
232+
return paths
233+
}
234+
205235
// Handle registers a new request handle with the given path and method.
206236
//
207237
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
@@ -227,7 +257,16 @@ func (r *Router) Handle(method, path string, handle fasthttp.RequestHandler) {
227257
r.trees[method] = root
228258
}
229259

230-
root.addRoute(path, handle)
260+
optionalPaths := getOptionalPaths(path)
261+
262+
// if not has optional paths, adds the original
263+
if len(optionalPaths) == 0 {
264+
root.addRoute(path, handle)
265+
} else {
266+
for _, p := range optionalPaths {
267+
root.addRoute(p, handle)
268+
}
269+
}
231270
}
232271

233272
// ServeFiles serves files from the given file system root.

router_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,33 @@ func TestRouterRoot(t *testing.T) {
222222
}
223223
}
224224

225+
func TestRouterOptionalPathArgs(t *testing.T) {
226+
handler := func(ctx *fasthttp.RequestCtx) {
227+
ctx.SetStatusCode(fasthttp.StatusOK)
228+
}
229+
230+
expectedPaths := []string{
231+
"/show/:name/",
232+
"/show/:name/:surname/",
233+
"/show/:name/:surname/at/",
234+
"/show/:name/:surname/at/:address/",
235+
"/show/:name/:surname/at/:address/:id/",
236+
"/show/:name/:surname/at/:address/:id/:phone/",
237+
}
238+
r := New()
239+
r.GET("/show/:name/:surname?/at/:address?/:id/:phone?", handler)
240+
241+
for _, path := range expectedPaths {
242+
ctx := new(fasthttp.RequestCtx)
243+
244+
h, _ := r.Lookup("GET", path, ctx)
245+
246+
if h == nil {
247+
t.Errorf("Expected optional path '%s' is not registered", path)
248+
}
249+
}
250+
}
251+
225252
func TestRouterChaining(t *testing.T) {
226253
r1 := New()
227254
r2 := New()

0 commit comments

Comments
 (0)