From af7d642797b83e92e0cb064d3c1de58096ce864d Mon Sep 17 00:00:00 2001 From: ThinhNX Date: Tue, 16 Jul 2024 10:33:56 +0700 Subject: [PATCH 1/7] /p/demo/mux/ support query strings --- examples/gno.land/p/demo/mux/query.gno | 51 ++++++++++++++++ examples/gno.land/p/demo/mux/query_test.gno | 67 +++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 examples/gno.land/p/demo/mux/query.gno create mode 100644 examples/gno.land/p/demo/mux/query_test.gno diff --git a/examples/gno.land/p/demo/mux/query.gno b/examples/gno.land/p/demo/mux/query.gno new file mode 100644 index 00000000000..d473eedb9bc --- /dev/null +++ b/examples/gno.land/p/demo/mux/query.gno @@ -0,0 +1,51 @@ +package mux + +import "strings" + +type UrlQuery map[string][]string + +/* + URL() returns a full map of key-listValue from request + to get a list of params by key, use: req.URL()["key"] + to get single param by key, use: req.URL().Get("key") +*/ +func (r *Request) URL() UrlQuery { + urlQueries := UrlQuery{} + reqParts := strings.Split(r.Path, "/") + for i := 0; i < len(reqParts); i++ { + rFullPath := reqParts[i] + switch { + // find the starting of query string + case strings.Contains(rFullPath, "?"): + { + index := strings.Index(rFullPath, "?") + // get the query path and the query string + // the rQueryPath may be used for handler for handling request path + // rQueryPath := rFullPath[:index] + queryString := rFullPath[index+1:] + params := strings.Split(queryString, "&") + for _, param := range params { + // find key - value of query params, then append to the UrlQuery + kv := strings.Split(param, "=") + if len(kv) == 2 { + urlQueries[kv[0]] = append(urlQueries[kv[0]], kv[1]) + } + } + } + default: + // continue + } + } + return urlQueries +} + +// get the query by key +// if there is more than one query, returns the very first param +func (qs UrlQuery) Get(key string) string { + listMatching, ok := qs[key] + if ok { + return listMatching[0] + } else { + return "" + } +} diff --git a/examples/gno.land/p/demo/mux/query_test.gno b/examples/gno.land/p/demo/mux/query_test.gno new file mode 100644 index 00000000000..058d93365f6 --- /dev/null +++ b/examples/gno.land/p/demo/mux/query_test.gno @@ -0,0 +1,67 @@ +package mux + +import ( + "fmt" + "testing" +) + +func TestQuery_Get(t *testing.T) { + cases := []struct { + name string + reqPath string + key string + expectedOutput string + }{ + // get by key + {"get_by_key_normal", "users/?name=testname&age=12", "name", "testname"}, + {"get_same_query", "users/user?name=name1&name=name2", "name", "name1"}, + {"get_by_key_unprocesspath", "users/unprocesspath?user=thinhnx&age=12", "user", "thinhnx"}, + } + + for _, tt := range cases { + name := fmt.Sprintf("%s-%s", tt.name, tt.reqPath) + t.Run(name, func(t *testing.T) { + req := &Request{ + HandlerPath: "", + Path: tt.reqPath, + } + output := req.URL().Get(tt.key) + if output != tt.expectedOutput { + t.Errorf("Expected %q, but got %q", tt.expectedOutput, output) + } + }) + } +} + + +func TestQuery_List(t *testing.T) { + cases := []struct { + name string + reqPath string + key string + expectedOutput []string + }{ + // get all queries + {"get_the_queries", "users/user?name=testname&age=12&name=thinhnx", "name", []string{"testname", "thinhnx"}}, + } + + for _, tt := range cases { + name := fmt.Sprintf("%s-%s", tt.name, tt.reqPath) + t.Run(name, func(t *testing.T) { + req := &Request{ + HandlerPath: "", + Path: tt.reqPath, + } + output := req.URL()[tt.key] + if len(output) != len(tt.expectedOutput) { + t.Errorf("Expected %q, but got %q", tt.expectedOutput, output) + } + listOutput := req.URL()[tt.key] + for i, ttExpt := range tt.expectedOutput { + if ttExpt != listOutput[i] { + t.Errorf("Expected %q, but got %q", ttExpt, listOutput[i]) + } + } + }) + } +} \ No newline at end of file From d622e8a2718bb414bac664c0f7f9ca23099f1b9f Mon Sep 17 00:00:00 2001 From: ThinhNX Date: Tue, 16 Jul 2024 11:45:46 +0700 Subject: [PATCH 2/7] update testcases and naming --- examples/gno.land/p/demo/mux/query.gno | 8 ++++---- examples/gno.land/p/demo/mux/query_test.gno | 22 +++++++++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/gno.land/p/demo/mux/query.gno b/examples/gno.land/p/demo/mux/query.gno index d473eedb9bc..aa458391fb9 100644 --- a/examples/gno.land/p/demo/mux/query.gno +++ b/examples/gno.land/p/demo/mux/query.gno @@ -5,11 +5,11 @@ import "strings" type UrlQuery map[string][]string /* - URL() returns a full map of key-listValue from request - to get a list of params by key, use: req.URL()["key"] - to get single param by key, use: req.URL().Get("key") + Query() returns a full map of key-listValue from request + to get a list of params by key, use: req.Query()["key"] + to get single param by key, use: req.Query().Get("key") */ -func (r *Request) URL() UrlQuery { +func (r *Request) Query() UrlQuery { urlQueries := UrlQuery{} reqParts := strings.Split(r.Path, "/") for i := 0; i < len(reqParts); i++ { diff --git a/examples/gno.land/p/demo/mux/query_test.gno b/examples/gno.land/p/demo/mux/query_test.gno index 058d93365f6..9e695b665ce 100644 --- a/examples/gno.land/p/demo/mux/query_test.gno +++ b/examples/gno.land/p/demo/mux/query_test.gno @@ -13,9 +13,10 @@ func TestQuery_Get(t *testing.T) { expectedOutput string }{ // get by key - {"get_by_key_normal", "users/?name=testname&age=12", "name", "testname"}, - {"get_same_query", "users/user?name=name1&name=name2", "name", "name1"}, - {"get_by_key_unprocesspath", "users/unprocesspath?user=thinhnx&age=12", "user", "thinhnx"}, + {"Get_query_key", "api/v1/?name=testname&age=12", "name", "testname"}, + {"Get_query_repeat", "api/v1/user?name=name1&name=name2&name=name3", "name", "name1"}, + {"Get_query_with_pre_path", "api/v1/unprocesspath?user=thinhnx&age=12", "user", "thinhnx"}, + {"Get_query_empty", "api/v1/?name=testname&age=12", "loc", ""}, } for _, tt := range cases { @@ -25,7 +26,7 @@ func TestQuery_Get(t *testing.T) { HandlerPath: "", Path: tt.reqPath, } - output := req.URL().Get(tt.key) + output := req.Query().Get(tt.key) if output != tt.expectedOutput { t.Errorf("Expected %q, but got %q", tt.expectedOutput, output) } @@ -34,7 +35,7 @@ func TestQuery_Get(t *testing.T) { } -func TestQuery_List(t *testing.T) { +func TestQuery_QueryList(t *testing.T) { cases := []struct { name string reqPath string @@ -42,7 +43,10 @@ func TestQuery_List(t *testing.T) { expectedOutput []string }{ // get all queries - {"get_the_queries", "users/user?name=testname&age=12&name=thinhnx", "name", []string{"testname", "thinhnx"}}, + {"get_name_list", "api/v1/user?name=name0&age=12&name=name1&age=30", "name", []string{"name0", "name1"}}, + {"get_age_list", "api/v1/user?name=name0&age=12&name=name1&age=30", "age", []string{"12", "30"}}, + {"get_loc_list", "api/v1/user?name=name0&age=12&name=name1&age=30&loc=HN", "loc", []string{"HN"}}, + {"get_empty_list", "api/v1/user?name=name0&age=12&name=name1&age=30&loc=HN", "addr", []string{}}, } for _, tt := range cases { @@ -52,11 +56,13 @@ func TestQuery_List(t *testing.T) { HandlerPath: "", Path: tt.reqPath, } - output := req.URL()[tt.key] + // simple check for length of expected and output list + output := req.Query()[tt.key] if len(output) != len(tt.expectedOutput) { t.Errorf("Expected %q, but got %q", tt.expectedOutput, output) } - listOutput := req.URL()[tt.key] + // check the corresponding elements + listOutput := req.Query()[tt.key] for i, ttExpt := range tt.expectedOutput { if ttExpt != listOutput[i] { t.Errorf("Expected %q, but got %q", ttExpt, listOutput[i]) From f85fdc0e2d9d47e5bb90533ebeb7214e566c3d2e Mon Sep 17 00:00:00 2001 From: ThinhNX Date: Tue, 16 Jul 2024 13:21:50 +0700 Subject: [PATCH 3/7] make fmt --- examples/gno.land/p/demo/mux/query.gno | 6 +++--- examples/gno.land/p/demo/mux/query_test.gno | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/gno.land/p/demo/mux/query.gno b/examples/gno.land/p/demo/mux/query.gno index aa458391fb9..2b55e683548 100644 --- a/examples/gno.land/p/demo/mux/query.gno +++ b/examples/gno.land/p/demo/mux/query.gno @@ -5,9 +5,9 @@ import "strings" type UrlQuery map[string][]string /* - Query() returns a full map of key-listValue from request - to get a list of params by key, use: req.Query()["key"] - to get single param by key, use: req.Query().Get("key") +Query() returns a full map of key-listValue from request +to get a list of params by key, use: req.Query()["key"] +to get single param by key, use: req.Query().Get("key") */ func (r *Request) Query() UrlQuery { urlQueries := UrlQuery{} diff --git a/examples/gno.land/p/demo/mux/query_test.gno b/examples/gno.land/p/demo/mux/query_test.gno index 9e695b665ce..1c73990eb94 100644 --- a/examples/gno.land/p/demo/mux/query_test.gno +++ b/examples/gno.land/p/demo/mux/query_test.gno @@ -34,7 +34,6 @@ func TestQuery_Get(t *testing.T) { } } - func TestQuery_QueryList(t *testing.T) { cases := []struct { name string @@ -70,4 +69,4 @@ func TestQuery_QueryList(t *testing.T) { } }) } -} \ No newline at end of file +} From fca704356ad075a40480287e437538bd50963ecc Mon Sep 17 00:00:00 2001 From: ThinhNX Date: Tue, 23 Jul 2024 01:48:14 +0700 Subject: [PATCH 4/7] support query strings, add testcases --- examples/gno.land/p/demo/mux/query.gno | 67 +++++++++++++------ examples/gno.land/p/demo/mux/query_test.gno | 37 ++++++++-- examples/gno.land/p/demo/mux/request.gno | 4 ++ examples/gno.land/p/demo/mux/request_test.gno | 3 + examples/gno.land/p/demo/mux/router.gno | 3 + examples/gno.land/p/demo/mux/router_test.gno | 26 +++++++ 6 files changed, 114 insertions(+), 26 deletions(-) diff --git a/examples/gno.land/p/demo/mux/query.gno b/examples/gno.land/p/demo/mux/query.gno index 2b55e683548..3a843587fb4 100644 --- a/examples/gno.land/p/demo/mux/query.gno +++ b/examples/gno.land/p/demo/mux/query.gno @@ -8,35 +8,49 @@ type UrlQuery map[string][]string Query() returns a full map of key-listValue from request to get a list of params by key, use: req.Query()["key"] to get single param by key, use: req.Query().Get("key") +to get request path use GetPath() */ -func (r *Request) Query() UrlQuery { + +func (r *Request) QueryFull() (UrlQuery, string) { urlQueries := UrlQuery{} - reqParts := strings.Split(r.Path, "/") - for i := 0; i < len(reqParts); i++ { - rFullPath := reqParts[i] + pathQuery := "" + // checking if there is query in r.Path + switch { + case strings.Contains(r.Path, "?"): + // get baseUrl and queryString + rParts := strings.SplitN(r.Path, "?", 2) + if len(rParts) == 1 { + // if this is not a `query string` query, then returns full path as queryPath + return urlQueries, rParts[0] + } + baseUrl := rParts[0] + queryString := rParts[1] + + // find the target path + baseUrlParts := strings.Split(baseUrl, "/") + rTargetPath := baseUrlParts[len(baseUrlParts)-1] + pathQuery = rTargetPath + + // process the queryString switch { - // find the starting of query string - case strings.Contains(rFullPath, "?"): - { - index := strings.Index(rFullPath, "?") - // get the query path and the query string - // the rQueryPath may be used for handler for handling request path - // rQueryPath := rFullPath[:index] - queryString := rFullPath[index+1:] - params := strings.Split(queryString, "&") - for _, param := range params { - // find key - value of query params, then append to the UrlQuery - kv := strings.Split(param, "=") - if len(kv) == 2 { - urlQueries[kv[0]] = append(urlQueries[kv[0]], kv[1]) - } + // find the first param index + case strings.Contains(queryString, "="): + for _, keyValue := range strings.Split(queryString, "&") { + parts := strings.SplitN(keyValue, "=", 2) + if len(parts) != 2 { + return urlQueries, rParts[0] } + key, value := parts[0], parts[1] + urlQueries[key] = append(urlQueries[key], value) } default: // continue } + + default: + // continue } - return urlQueries + return urlQueries, pathQuery } // get the query by key @@ -45,7 +59,16 @@ func (qs UrlQuery) Get(key string) string { listMatching, ok := qs[key] if ok { return listMatching[0] - } else { - return "" } + return "" +} + +func (r *Request) Query() UrlQuery { + uQuery, _ := r.QueryFull() + return uQuery +} + +func (r *Request) GetQueryPath() string { + _, pQuery := r.QueryFull() + return pQuery } diff --git a/examples/gno.land/p/demo/mux/query_test.gno b/examples/gno.land/p/demo/mux/query_test.gno index 1c73990eb94..22a7ed5b891 100644 --- a/examples/gno.land/p/demo/mux/query_test.gno +++ b/examples/gno.land/p/demo/mux/query_test.gno @@ -17,6 +17,8 @@ func TestQuery_Get(t *testing.T) { {"Get_query_repeat", "api/v1/user?name=name1&name=name2&name=name3", "name", "name1"}, {"Get_query_with_pre_path", "api/v1/unprocesspath?user=thinhnx&age=12", "user", "thinhnx"}, {"Get_query_empty", "api/v1/?name=testname&age=12", "loc", ""}, + {"Get_query_with_slash", "api/v1/?name=testname&endpoint=testdomain.com/v1/with/slash/", "endpoint", "testdomain.com/v1/with/slash/"}, + {"Get_query_with_extra_slash", "api/v1/unprocesspath?user=thinhnx&age=12&addr=12/34/NewYork//", "addr", "12/34/NewYork//"}, } for _, tt := range cases { @@ -42,10 +44,10 @@ func TestQuery_QueryList(t *testing.T) { expectedOutput []string }{ // get all queries - {"get_name_list", "api/v1/user?name=name0&age=12&name=name1&age=30", "name", []string{"name0", "name1"}}, - {"get_age_list", "api/v1/user?name=name0&age=12&name=name1&age=30", "age", []string{"12", "30"}}, - {"get_loc_list", "api/v1/user?name=name0&age=12&name=name1&age=30&loc=HN", "loc", []string{"HN"}}, - {"get_empty_list", "api/v1/user?name=name0&age=12&name=name1&age=30&loc=HN", "addr", []string{}}, + {"Get_name_list", "api/v1/user?name=name0&age=12&name=name1&age=30", "name", []string{"name0", "name1"}}, + {"Get_age_list", "api/v1/user?name=name0&age=12&name=name1&age=30", "age", []string{"12", "30"}}, + {"Get_loc_list", "api/v1/user?name=name0&age=12&name=name1&age=30&loc=HN", "loc", []string{"HN"}}, + {"Get_empty_list", "api/v1/user?name=name0&age=12&name=name1&age=30&loc=HN", "addr", []string{}}, } for _, tt := range cases { @@ -70,3 +72,30 @@ func TestQuery_QueryList(t *testing.T) { }) } } + +func TestQuery_GetPath(t *testing.T) { + cases := []struct { + name string + reqPath string + expectedOutput string + }{ + // get all queries + {"Get_user", "api/v1/user?name=name1&name=name2&name=name3", "user"}, + {"Get_empty_path", "api/v1/?user=thinhnx&age=12&addr=12/34/NewYork", ""}, + } + + for _, tt := range cases { + name := fmt.Sprintf("%s-%s", tt.name, tt.reqPath) + t.Run(name, func(t *testing.T) { + req := &Request{ + HandlerPath: "", + Path: tt.reqPath, + } + // check the corresponding elements + outputGP := req.GetQueryPath() + if tt.expectedOutput != outputGP { + t.Errorf("Expected %q, but got %q", tt.expectedOutput, outputGP) + } + }) + } +} diff --git a/examples/gno.land/p/demo/mux/request.gno b/examples/gno.land/p/demo/mux/request.gno index f7996fe40fe..d8057910e3f 100644 --- a/examples/gno.land/p/demo/mux/request.gno +++ b/examples/gno.land/p/demo/mux/request.gno @@ -24,6 +24,10 @@ func (r *Request) GetVar(key string) string { case strings.HasPrefix(handlerPart, "{") && strings.HasSuffix(handlerPart, "}"): parameter := handlerPart[1 : len(handlerPart)-1] if parameter == key { + // check if this request has query strings or not + if strings.Contains(reqParts[i], "?") { + return strings.Split(reqParts[i], "?")[0] + } return reqParts[i] } default: diff --git a/examples/gno.land/p/demo/mux/request_test.gno b/examples/gno.land/p/demo/mux/request_test.gno index 5f8088b4964..3677193e91e 100644 --- a/examples/gno.land/p/demo/mux/request_test.gno +++ b/examples/gno.land/p/demo/mux/request_test.gno @@ -18,6 +18,9 @@ func TestRequest_GetVar(t *testing.T) { {"a/{b}/c/{d}", "a/42/c/1337", "b", "42"}, {"a/{b}/c/{d}", "a/42/c/1337", "d", "1337"}, {"{a}", "foo", "a", "foo"}, + {"/api/v1/{user}", "/api/v1/testuser?name=test", "user", "testuser"}, + {"/api/{v}/{user}/long/slash", "/api/v1/testuser?name=test/long/slash", "v", "v1"}, + {"/api/v1/{user}/long/slash", "/api/v1/testuser?name=test/long/slash", "user", "testuser"}, // TODO: wildcards: a/*/c // TODO: multiple patterns per slashes: a/{b}-{c}/d } diff --git a/examples/gno.land/p/demo/mux/router.gno b/examples/gno.land/p/demo/mux/router.gno index a2efb3a4ebf..504f5b4b478 100644 --- a/examples/gno.land/p/demo/mux/router.gno +++ b/examples/gno.land/p/demo/mux/router.gno @@ -32,6 +32,9 @@ func (r *Router) Render(reqPath string) string { patPart := patParts[i] reqPart := reqParts[i] + if strings.Contains(patPart, "?") { + continue + } if patPart == "*" { continue } diff --git a/examples/gno.land/p/demo/mux/router_test.gno b/examples/gno.land/p/demo/mux/router_test.gno index 13fd5b97955..1c636db895b 100644 --- a/examples/gno.land/p/demo/mux/router_test.gno +++ b/examples/gno.land/p/demo/mux/router_test.gno @@ -17,6 +17,29 @@ func TestRouter_Render(t *testing.T) { res.Write("Hi, earth!") }) + // handler func for query case + router.HandleFunc("hello/{user}/?", func(res *ResponseWriter, req *Request) { + name := req.GetVar("user") + queryPath := req.GetQueryPath() + urlQ := req.Query() + + if len(urlQ) != 0 && queryPath != "" { + queryNum := 0 + dataToWrite := "" + for key, values := range urlQ { + queryNum++ + valuesResult := "" + for _, vl := range values { + valuesResult += vl + "," + } + dataToWrite += " key: " + key + " and value: " + valuesResult + } + res.Write("Hello, " + name + " with path " + queryPath + " ===" + dataToWrite) + } else { + res.Write("Hello, world!") + } + }) + cases := []struct { path string expectedOutput string @@ -24,6 +47,9 @@ func TestRouter_Render(t *testing.T) { {"hello/Alice", "Hello, Alice!"}, {"hi", "Hi, earth!"}, {"hello/Bob", "Hello, Bob!"}, + {"hello/Bob/action?testaction=punch", "Hello, Bob with path action === key: testaction and value: punch,"}, + {"hello/Alice/finding?docs=gno&book=gnobook", "Hello, Alice with path finding === key: docs and value: gno, key: book and value: gnobook,"}, + {"hello/Celena/finding?color=red&color=blue", "Hello, Celena with path finding === key: color and value: red,blue,"}, // TODO: {"hello", "Hello, world!"}, // TODO: hello/, /hello, hello//Alice, hello/Alice/, hello/Alice/Bob, etc } From 29d1b9f9608833c8ae08e9e356e6be0871323d26 Mon Sep 17 00:00:00 2001 From: ThinhNX Date: Wed, 24 Jul 2024 05:07:48 +0700 Subject: [PATCH 5/7] refact coding --- examples/gno.land/p/demo/mux/query.gno | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/examples/gno.land/p/demo/mux/query.gno b/examples/gno.land/p/demo/mux/query.gno index 3a843587fb4..0e05a45b6bd 100644 --- a/examples/gno.land/p/demo/mux/query.gno +++ b/examples/gno.land/p/demo/mux/query.gno @@ -15,8 +15,7 @@ func (r *Request) QueryFull() (UrlQuery, string) { urlQueries := UrlQuery{} pathQuery := "" // checking if there is query in r.Path - switch { - case strings.Contains(r.Path, "?"): + if strings.Contains(r.Path, "?") { // get baseUrl and queryString rParts := strings.SplitN(r.Path, "?", 2) if len(rParts) == 1 { @@ -32,9 +31,8 @@ func (r *Request) QueryFull() (UrlQuery, string) { pathQuery = rTargetPath // process the queryString - switch { // find the first param index - case strings.Contains(queryString, "="): + if strings.Contains(queryString, "=") { for _, keyValue := range strings.Split(queryString, "&") { parts := strings.SplitN(keyValue, "=", 2) if len(parts) != 2 { @@ -43,12 +41,7 @@ func (r *Request) QueryFull() (UrlQuery, string) { key, value := parts[0], parts[1] urlQueries[key] = append(urlQueries[key], value) } - default: - // continue } - - default: - // continue } return urlQueries, pathQuery } From 1b42c68ef1eb3440846c6a01264f6f6a7bfaf783 Mon Sep 17 00:00:00 2001 From: ThinhNX Date: Wed, 24 Jul 2024 05:10:31 +0700 Subject: [PATCH 6/7] refact var name --- examples/gno.land/p/demo/mux/query.gno | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/gno.land/p/demo/mux/query.gno b/examples/gno.land/p/demo/mux/query.gno index 0e05a45b6bd..dc464750f3c 100644 --- a/examples/gno.land/p/demo/mux/query.gno +++ b/examples/gno.land/p/demo/mux/query.gno @@ -2,7 +2,7 @@ package mux import "strings" -type UrlQuery map[string][]string +type QueryValues map[string][]string /* Query() returns a full map of key-listValue from request @@ -11,8 +11,8 @@ to get single param by key, use: req.Query().Get("key") to get request path use GetPath() */ -func (r *Request) QueryFull() (UrlQuery, string) { - urlQueries := UrlQuery{} +func (r *Request) QueryFull() (QueryValues, string) { + urlQueries := QueryValues{} pathQuery := "" // checking if there is query in r.Path if strings.Contains(r.Path, "?") { @@ -48,7 +48,7 @@ func (r *Request) QueryFull() (UrlQuery, string) { // get the query by key // if there is more than one query, returns the very first param -func (qs UrlQuery) Get(key string) string { +func (qs QueryValues) Get(key string) string { listMatching, ok := qs[key] if ok { return listMatching[0] @@ -56,7 +56,7 @@ func (qs UrlQuery) Get(key string) string { return "" } -func (r *Request) Query() UrlQuery { +func (r *Request) Query() QueryValues { uQuery, _ := r.QueryFull() return uQuery } From 48a0eaa0cf2c19a2ec149cf0f1aa5c0930e0b7b3 Mon Sep 17 00:00:00 2001 From: ThinhNX Date: Wed, 24 Jul 2024 05:19:55 +0700 Subject: [PATCH 7/7] just check pattern prefix --- examples/gno.land/p/demo/mux/router.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/p/demo/mux/router.gno b/examples/gno.land/p/demo/mux/router.gno index 504f5b4b478..1d46b91cc79 100644 --- a/examples/gno.land/p/demo/mux/router.gno +++ b/examples/gno.land/p/demo/mux/router.gno @@ -32,7 +32,7 @@ func (r *Router) Render(reqPath string) string { patPart := patParts[i] reqPart := reqParts[i] - if strings.Contains(patPart, "?") { + if strings.HasPrefix(patPart, "?") { continue } if patPart == "*" {