From c19aa0598b6bab47f498e68ebc60ceafded8631f Mon Sep 17 00:00:00 2001 From: Eason Lin Date: Wed, 19 Jul 2017 15:50:05 +0800 Subject: [PATCH] feat(context): add BindQuery func (#1029) * feat(context): add BindQuery func, only parse/bind the query string params. * docs(readme): add BindQuery section. * docs(readme): fix import. * docs(readme): separate import --- README.md | 38 +++++++++++++++++++++++++++++++++++++- binding/binding.go | 1 + binding/binding_test.go | 27 +++++++++++++++++++++++++++ binding/query.go | 23 +++++++++++++++++++++++ context.go | 5 +++++ context_test.go | 16 ++++++++++++++++ 6 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 binding/query.go diff --git a/README.md b/README.md index 07fc960e..35858737 100644 --- a/README.md +++ b/README.md @@ -460,7 +460,43 @@ func main() { } ``` -### Bind Query String +### Only Bind Query String + +`BindQuery` function only binds the query params and not the post data. See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-315953017). + +```go +package main + +import ( + "log" + + "github.com/gin-gonic/gin" +) + +type Person struct { + Name string `form:"name"` + Address string `form:"address"` +} + +func main() { + route := gin.Default() + route.Any("/testing", startPage) + route.Run(":8085") +} + +func startPage(c *gin.Context) { + var person Person + if c.BindQuery(&person) == nil { + log.Println("====== Only Bind By Query String ======") + log.Println(person.Name) + log.Println(person.Address) + } + c.String(200, "Success") +} + +``` + +### Bind Query String or Post Data See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292). 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 306e2055..87aa1bea 100644 --- a/context.go +++ b/context.go @@ -467,6 +467,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)