Repository: gobuffalo/buffalo
Pull request #1778 (2019-08-29 11:29:55)

Append URL and Query String parameter dupplicates
Fix to issue #1777

A quick fix to be able to manage duplicates in URL Params and query string params.

### Example :
**route**: `GET /users/{user_id}`

**call**: `GET /users/001?user_id=002&user_id=003`

#### Previous Behavior
**`c.Params()`**:
```json
{
    "user_id": [
        "003"
    ]
}
```
**`c.Param("user_id")`**: `"003"`

#### New Behavior
**`c.Params()`**:
```json
{
    "user_id": [
        "001",
        "002",
        "003",
    ]
}
```
**`c.Param("user_id")`**: `"001"`


Max-Pol: > Can you please add tests for this? Thanks.

I added tests, sorry I should have done it before... 

Thanks for this awesome project btw :)

Patch:
diff --git a/context.go b/context.go
index 1c720172..770f6b8c 100644
--- a/context.go
+++ b/context.go
@@ -3,6 +3,7 @@ package buffalo
 import (
 	"context"
 	"net/http"
+	"net/url"
 	"sync"
 
 	"github.com/gobuffalo/buffalo/binding"
@@ -46,16 +47,21 @@ func (a *App) newContext(info RouteInfo, res http.ResponseWriter, req *http.Requ
 	if ws, ok := res.(*Response); ok {
 		res = ws
 	}
-	params := req.URL.Query()
+
+	// Parse URL Params
+	params := url.Values{}
 	vars := mux.Vars(req)
 	for k, v := range vars {
-		params.Set(k, v)
+		params.Add(k, v)
 	}
 
+	// Parse URL Query String Params
+	// For POST, PUT, and PATCH requests, it also parse the request body as a form.
+	// Request body parameters take precedence over URL query string values in params
 	if err := req.ParseForm(); err == nil {
 		for k, v := range req.Form {
 			for _, vv := range v {
-				params.Set(k, vv)
+				params.Add(k, vv)
 			}
 		}
 	}
diff --git a/go.mod b/go.mod
index 880cf74a..c55c26d1 100644
--- a/go.mod
+++ b/go.mod
@@ -42,7 +42,7 @@ require (
 	github.com/spf13/viper v1.4.0
 	github.com/stretchr/testify v1.4.0
 	golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
-	golang.org/x/tools v0.0.0-20191017101817-846f856e7d71
+	golang.org/x/tools v0.0.0-20191017163857-e4d7c6f25b8e
 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc
 	gopkg.in/yaml.v2 v2.2.4
 )
diff --git a/go.sum b/go.sum
index 9682b064..88aff110 100644
--- a/go.sum
+++ b/go.sum
@@ -1043,6 +1043,8 @@ golang.org/x/tools v0.0.0-20190905035308-adb45749da8e/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20190906203814-12febf440ab1/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191017163857-e4d7c6f25b8e h1:DpwXve8B+hJ9vwDDTRZ4nMMM6qjYPQ5bq0OfRXTKJJY=
+golang.org/x/tools v0.0.0-20191017163857-e4d7c6f25b8e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191017101817-846f856e7d71 h1:gKvBHiwvrwjVESSCHvRLeyg2OLVRH6UwgwczU5CXvcg=
 golang.org/x/tools v0.0.0-20191017101817-846f856e7d71/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/runtime/version.go b/runtime/version.go
index 42cff956..5dd9aaf1 100644
--- a/runtime/version.go
+++ b/runtime/version.go
@@ -1,4 +1,4 @@
 package runtime
 
 // Version is the current version of the buffalo binary
-const Version = "development"
+const Version = "v0.14.11"


Test patch:
diff --git a/default_context_test.go b/default_context_test.go
index 3ba84c78..72e88920 100644
--- a/default_context_test.go
+++ b/default_context_test.go
@@ -107,6 +107,32 @@ func Test_DefaultContext_Param_form(t *testing.T) {
 	r.Equal("Mark", name)
 }
 
+func Test_DefaultContext_Param_Multiple(t *testing.T) {
+	r := require.New(t)
+
+	app := New(Options{})
+	var params ParamValues
+	var param string
+	app.POST("/{id}", func(c Context) error {
+		params = c.Params()
+		param = c.Param("id")
+		return nil
+	})
+
+	w := httptest.New(app)
+	res := w.HTML("/a?id=c&y=z&id=d").Post(map[string]string{
+		"id": "b",
+	})
+	paramsExpected := url.Values{
+		"id": []string{"a", "b", "c", "d"},
+		"y":  []string{"z"},
+	}
+
+	r.Equal(200, res.Code)
+	r.Equal(paramsExpected, params.(url.Values))
+	r.Equal("a", param)
+}
+
 func Test_DefaultContext_GetSet(t *testing.T) {
 	r := require.New(t)
 	c := basicContext()