Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to bind query string? #742

Closed
selvam347 opened this issue Nov 16, 2016 · 22 comments
Closed

how to bind query string? #742

selvam347 opened this issue Nov 16, 2016 · 22 comments

Comments

@selvam347
Copy link

selvam347 commented Nov 16, 2016

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.

@ei-grad
Copy link

ei-grad commented Dec 1, 2016

+1 for c.BindQuery

@appleboy
Copy link
Member

appleboy commented Dec 3, 2016

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"`
}

@appleboy appleboy closed this as completed Dec 3, 2016
@jasonab
Copy link

jasonab commented Dec 3, 2016

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.

@ei-grad
Copy link

ei-grad commented Dec 3, 2016

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

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

@jasonab
Copy link

jasonab commented Dec 3, 2016

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

@appleboy
Copy link
Member

appleboy commented Dec 4, 2016

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. 😄

@appleboy
Copy link
Member

appleboy commented Dec 4, 2016

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

@ei-grad
Copy link

ei-grad commented Dec 4, 2016

Maybe we need to add bind query example on documents. 😄

It would be great.

@deankarn
Copy link

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.

@mehdy
Copy link
Contributor

mehdy commented Dec 22, 2016

+1 for BindQuery

@appleboy
Copy link
Member

@mehdy See the comment #742 (comment)

appleboy added a commit that referenced this issue Dec 23, 2016
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
@appleboy
Copy link
Member

I make new PR to improve document. #772

@deankarn
Copy link

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.

@appleboy
Copy link
Member

appleboy commented Dec 23, 2016

#742 (comment)

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)
	}

@deankarn
Copy link

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.

@mehdy
Copy link
Contributor

mehdy commented Dec 23, 2016

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

@easonlin404
Copy link
Contributor

easonlin404 commented Jul 18, 2017

Only Bind Query String

See PR #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

@javierprovecho
Copy link
Member

#1029 merged

@xgz123
Copy link

xgz123 commented Sep 25, 2018

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

@tprei
Copy link

tprei commented Jun 11, 2021

does this only work with shouldBindQuery? I am using shouldBindWith(..., binding.Query) and it's outputing and error for a missing reuired json tag

I think shouldBindWith should have the same behaviour

@Linhieng
Copy link

Linhieng commented May 16, 2022

I arrived here from this URL, and then this reproduces it, and finds that it is different from the above output

Whether I send a request with query or json, he recognizes it as a json type.

$ curl -X GET localhost:8085/testing --data '{"name":"JJ", "address":"xyz"}' -H "Content-Type:application/json"
Successcurl: (3) unmatched close brace/bracket in URL position 12:
address:xyz}'
           ^

and now I ignored the argument and passed an empty piece of data:

$ curl -X GET localhost:8085/testing --data "" -H "Content-Type:application/json"
Success

but in the terminal:

[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 200   
[GIN] 2022/05/16 - 17:13:11 | 200 |      3.1717ms |       127.0.0.1 | GET      "/testing"
2022/05/16 17:16:10 ====== Bind By Query String ======
2022/05/16 17:16:10 
2022/05/16 17:16:10

Is anyone having the same problem as me?

@Mai-Lapyst
Copy link

I arrived here from this URL, and then this reproduces it, and finds that it is different from the above output

Whether I send a request with query or json, he recognizes it as a json type.

$ curl -X GET localhost:8085/testing --data '{"name":"JJ", "address":"xyz"}' -H "Content-Type:application/json"
Successcurl: (3) unmatched close brace/bracket in URL position 12:
address:xyz}'
           ^

and now I ignored the argument and passed an empty piece of data:

$ curl -X GET localhost:8085/testing --data "" -H "Content-Type:application/json"
Success

but in the terminal:

[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 200   
[GIN] 2022/05/16 - 17:13:11 | 200 |      3.1717ms |       127.0.0.1 | GET      "/testing"
2022/05/16 17:16:10 ====== Bind By Query String ======
2022/05/16 17:16:10 
2022/05/16 17:16:10

Is anyone having the same problem as me?

There are serveral things wrong here:

  • First of, body data in a GET request is by a bunch of frameworks not supported (or atleast not fully) since also the HTTP spec dosnt want you to send data when using GET; thats what they designed POST, PUT, PATCH for.
  • Curl respects the point above and tries to encode your data into the URL instead of the body, hence you get the "unmatched close brace/bracket in URL" error.
  • When ignoring the data (you simply give it an empty string) it therefore also dosnt send any data (either body nor query) and therefore your output also have empty lines, since again: your data is empty as well.

Hope this could help you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests