Browse Source

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
Eason Lin 8 years ago
parent
commit
c19aa0598b
6 changed files with 109 additions and 1 deletions
  1. 37 1
      README.md
  2. 1 0
      binding/binding.go
  3. 27 0
      binding/binding_test.go
  4. 23 0
      binding/query.go
  5. 5 0
      context.go
  6. 16 0
      context_test.go

+ 37 - 1
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).
 See the [detail information](https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292).
 
 

+ 1 - 0
binding/binding.go

@@ -39,6 +39,7 @@ var (
 	JSON          = jsonBinding{}
 	JSON          = jsonBinding{}
 	XML           = xmlBinding{}
 	XML           = xmlBinding{}
 	Form          = formBinding{}
 	Form          = formBinding{}
+	Query         = queryBinding{}
 	FormPost      = formPostBinding{}
 	FormPost      = formPostBinding{}
 	FormMultipart = formMultipartBinding{}
 	FormMultipart = formMultipartBinding{}
 	ProtoBuf      = protobufBinding{}
 	ProtoBuf      = protobufBinding{}

+ 27 - 0
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) {
 func TestBindingXML(t *testing.T) {
 	testBodyBinding(t,
 	testBodyBinding(t,
 		XML, "xml",
 		XML, "xml",
@@ -204,6 +216,21 @@ func testFormBinding(t *testing.T, method, path, badPath, body, badBody string)
 	assert.Error(t, err)
 	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) {
 func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
 	assert.Equal(t, b.Name(), name)
 	assert.Equal(t, b.Name(), name)
 
 

+ 23 - 0
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)
+}

+ 5 - 0
context.go

@@ -467,6 +467,11 @@ func (c *Context) BindJSON(obj interface{}) error {
 	return c.MustBindWith(obj, binding.JSON)
 	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
 // MustBindWith binds the passed struct pointer using the specified binding
 // engine. It will abort the request with HTTP 400 if any error ocurrs.
 // engine. It will abort the request with HTTP 400 if any error ocurrs.
 // See the binding package.
 // See the binding package.

+ 16 - 0
context_test.go

@@ -1186,6 +1186,22 @@ func TestContextBindWithJSON(t *testing.T) {
 	assert.Equal(t, w.Body.Len(), 0)
 	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) {
 func TestContextBadAutoBind(t *testing.T) {
 	w := httptest.NewRecorder()
 	w := httptest.NewRecorder()
 	c, _ := CreateTestContext(w)
 	c, _ := CreateTestContext(w)