diff --git a/binding/binding.go b/binding/binding.go index 1dbf2460..971547c2 100644 --- a/binding/binding.go +++ b/binding/binding.go @@ -39,6 +39,7 @@ var ( JSON = jsonBinding{} XML = xmlBinding{} Form = formBinding{} + Query = queryBinding{} FormPost = formPostBinding{} FormMultipart = formMultipartBinding{} ProtoBuf = protobufBinding{} diff --git a/binding/binding_test.go b/binding/binding_test.go index d7cdf77a..5575e166 100644 --- a/binding/binding_test.go +++ b/binding/binding_test.go @@ -67,6 +67,18 @@ func TestBindingForm2(t *testing.T) { "", "") } +func TestBindingQuery(t *testing.T) { + testQueryBinding(t, "POST", + "/?foo=bar&bar=foo", "/", + "foo=unused", "bar2=foo") +} + +func TestBindingQuery2(t *testing.T) { + testQueryBinding(t, "GET", + "/?foo=bar&bar=foo", "/?bar2=foo", + "foo=unused", "") +} + func TestBindingXML(t *testing.T) { testBodyBinding(t, XML, "xml", @@ -204,6 +216,21 @@ func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) assert.Error(t, err) } +func testQueryBinding(t *testing.T, method, path, badPath, body, badBody string) { + b := Query + assert.Equal(t, b.Name(), "query") + + obj := FooBarStruct{} + req := requestWithBody(method, path, body) + if method == "POST" { + req.Header.Add("Content-Type", MIMEPOSTForm) + } + err := b.Bind(req, &obj) + assert.NoError(t, err) + assert.Equal(t, obj.Foo, "bar") + assert.Equal(t, obj.Bar, "foo") +} + func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) { assert.Equal(t, b.Name(), name) diff --git a/binding/query.go b/binding/query.go new file mode 100644 index 00000000..a789f798 --- /dev/null +++ b/binding/query.go @@ -0,0 +1,23 @@ +// Copyright 2017 Manu Martinez-Almeida. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package binding + +import ( + "net/http" +) + +type queryBinding struct{} + +func (queryBinding) Name() string { + return "query" +} + +func (queryBinding) Bind(req *http.Request, obj interface{}) error { + values := req.URL.Query() + if err := mapForm(obj, values); err != nil { + return err + } + return validate(obj) +} diff --git a/context.go b/context.go index f29464d7..311da642 100644 --- a/context.go +++ b/context.go @@ -468,6 +468,11 @@ func (c *Context) BindJSON(obj interface{}) error { return c.MustBindWith(obj, binding.JSON) } +// BindQuery is a shortcut for c.MustBindWith(obj, binding.Query) +func (c *Context) BindQuery(obj interface{}) error { + return c.MustBindWith(obj, binding.Query) +} + // MustBindWith binds the passed struct pointer using the specified binding // engine. It will abort the request with HTTP 400 if any error ocurrs. // See the binding package. diff --git a/context_test.go b/context_test.go index db960fb3..15569bf2 100644 --- a/context_test.go +++ b/context_test.go @@ -1186,6 +1186,22 @@ func TestContextBindWithJSON(t *testing.T) { assert.Equal(t, w.Body.Len(), 0) } +func TestContextBindWithQuery(t *testing.T) { + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + + c.Request, _ = http.NewRequest("POST", "/?foo=bar&bar=foo", bytes.NewBufferString("foo=unused")) + + var obj struct { + Foo string `form:"foo"` + Bar string `form:"bar"` + } + assert.NoError(t, c.BindQuery(&obj)) + assert.Equal(t, "foo", obj.Bar) + assert.Equal(t, "bar", obj.Foo) + assert.Equal(t, 0, w.Body.Len()) +} + func TestContextBadAutoBind(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w)