Gin: how to bind query string?

Created on 16 Nov 2016  路  19Comments  路  Source: gin-gonic/gin

package main

import "log"
import "github.com/gin-gonic/gin"

type Person struct {
    Name    string `json:"name"`
    Address string `json:"address"`
}

func main() {
    log.Println("Hello World")
    route := gin.Default()
    route.GET("/testing", startPage)
    route.Run(":8085")
}

func startPage(c *gin.Context) {
    var person Person
    if c.BindJSON(&person) == nil {
        log.Println(person.Name)
        log.Println(person.Address)
        log.Println("Binding success...............")
    } else {
        log.Println("Binding failed...............")
    }

    c.String(200, "Success")
}

The above code works only for curl -X GET localhost:8085/testing --data '{"name":"JJ", "address":"xyz"}' -H "Content-Type:application/json" but not curl -X GET localhost:8085/testing?name=JJ&address=xyz -H "Content-Type:application/json"

if i use c.Bind(&person), binding failed both case.
How can i write the above code which binds both query string and json.

enhancement help wanted question

Most helpful comment

The following example is working for me.

package main

import "log"
import "github.com/gin-gonic/gin"

type Person struct {
    Name    string `form:"name" json:"name"`
    Address string `form:"address" json:"address"`
}

func main() {
    route := gin.Default()
    route.GET("/testing", startPage)
    route.Run(":8085")
}

func startPage(c *gin.Context) {
    var person Person
    if c.Bind(&person) == nil {
        log.Println("====== Bind By Query String ======")
        log.Println(person.Name)
        log.Println(person.Address)
    }

    if c.BindJSON(&person) == nil {
        log.Println("====== Bind By JSON ======")
        log.Println(person.Name)
        log.Println(person.Address)
    }

    c.String(200, "Success")
}

And try the following command:

# bind by query
$ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz"
# bind by json
$ curl -X GET localhost:8085/testing --data '{"name":"JJ", "address":"xyz"}' -H "Content-Type:application/json"

screen shot 2016-12-04 at 10 56 58 am

You can find the example from the following URL:

https://github.com/gin-gonic/gin#model-binding-and-validation

Maybe we need to add bind query example on documents. 馃槃

All 19 comments

+1 for c.BindQuery

We don't need c.BindQuery.

Try c.Bind for query string and post data:

type Person struct {
    Name    string `form:"name"`
    Address string `form:"address"`
}

Try c.BindJSON for JSON data:

type Person struct {
    Name    string `json:"name"`
    Address string `json:"address"`
}

Looking over the binding code, I don't see anywhere that it accesses req.URL.Query(). I don't understand how we can bind query parameters without that.

@jasonab it uses http.Request.Form, which contains query params.

@appleboy thanks! This is absolutely not clear from docs. :-(

@ei-grad Thanks, that was non-obvious :-)

The following example is working for me.

package main

import "log"
import "github.com/gin-gonic/gin"

type Person struct {
    Name    string `form:"name" json:"name"`
    Address string `form:"address" json:"address"`
}

func main() {
    route := gin.Default()
    route.GET("/testing", startPage)
    route.Run(":8085")
}

func startPage(c *gin.Context) {
    var person Person
    if c.Bind(&person) == nil {
        log.Println("====== Bind By Query String ======")
        log.Println(person.Name)
        log.Println(person.Address)
    }

    if c.BindJSON(&person) == nil {
        log.Println("====== Bind By JSON ======")
        log.Println(person.Name)
        log.Println(person.Address)
    }

    c.String(200, "Success")
}

And try the following command:

# bind by query
$ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz"
# bind by json
$ curl -X GET localhost:8085/testing --data '{"name":"JJ", "address":"xyz"}' -H "Content-Type:application/json"

screen shot 2016-12-04 at 10 56 58 am

You can find the example from the following URL:

https://github.com/gin-gonic/gin#model-binding-and-validation

Maybe we need to add bind query example on documents. 馃槃

@jasonab @ei-grad I will update document asap.

Maybe we need to add bind query example on documents. 馃槃

It would be great.

What if you posted values and had query string params how would you only parse/bind the query string params.

Bind always uses r.Form which is a combination of posted values and query params...same goes for only wanting to parse/bind r.PostForm and not wanting query string.

+1 for BindQuery

I make new PR to improve document. https://github.com/gin-gonic/gin/pull/772

So @appleboy if you posted data and had Query string params how could you ONLY bind the Query string params or ONLY bind posted data?

It seems like my previous comment was just overlooked.

https://github.com/gin-gonic/gin/issues/742#issuecomment-264681292

Do you see the screenshot?

only bind the query or post data

    if c.Bind(&person) == nil {
        log.Println("====== Bind By Query String ======")
        log.Println(person.Name)
        log.Println(person.Address)
    }

only bind the json data

    if c.BindJSON(&person) == nil {
        log.Println("====== Bind By JSON ======")
        log.Println(person.Name)
        log.Println(person.Address)
    }

Yes @appleboy I did see the screenshot,

your example is for Query params and JSON and my example was posting Form Data and Query params.

What if someone wanted to ONLY bind the Query Params and not the form data.

that's exactly the point! I think we need an BindQuery function that only binds the query params and not the post data in case some one is using both together

Only Bind Query String

See PR https://github.com/gin-gonic/gin/pull/1029. Add c.BindQuery function that only binds the query params and not the post data.

package main

import "log"
import "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 Query String ======")
        log.Println(person.Name)
        log.Println(person.Address)
    }
    c.String(200, "Success")
}

Try the following command:

# only bind query
$ curl -X GET "localhost:8085/testing?name=eason&address=xyz"

# only bind query string, ignore form data
$ curl -X POST "localhost:8085/testing?name=eason&address=xyz" --data 'name=ignore&address=ignore' -H "Content-Type:application/x-www-form-urlencoded"

Will Output:
2017-07-18 12 09 57

1029 merged

We don't need c.BindQuery.

Try c.Bind for query string and post data:

type Person struct {
  Name    string `form:"name"`
  Address string `form:"address"`
}

Try c.BindJSON for JSON data:

type Person struct {
  Name    string `json:"name"`
  Address string `json:"address"`
}

bindQuery also works with "form" tag

Was this page helpful?
0 / 5 - 0 ratings