gin
gin copied to clipboard
Can i bind uri and query to a struct in one method?
Description
Can i bind uri and query in one method? Currently when i bind uri , it will return an error because of binding of query is empty.
Maybe we need a BindUrl
function ?
How to reproduce
package main
import (
"github.com/gin-gonic/gin"
"log"
)
type DatasourceListRequest struct {
Name string `uri:"name" binding:"required"`
Query string `form:"query" binding:"required""`
}
func main() {
g := gin.Default()
g.GET("/hello/:name", Handler)
g.Run(":9000")
}
func Handler(ctx *gin.Context) {
var req = new(DatasourceListRequest)
if err := ctx.ShouldBindUri(req); err != nil {
log.Println("bind uri error")
}
if err := ctx.ShouldBindQuery(req); err != nil {
log.Println("bind query error")
}
}
func Handler(ctx *gin.Context) { var req = new(DatasourceListRequest) if err := ctx.ShouldBindBodyWith(&req, binding.Uri); err != nil { log.Println("bind uri error") } if err := ctx.ShouldBindBodyWith(&req, binding.Query); err != nil { log.Println("bind query error") } }
Sorry, i can't compile the code as the error is:
Cannot use 'binding.Uri' (type uriBinding) as the type binding.BindingBody Type does not implement 'binding.BindingBody' as some methods are missing: Bind(*http.Request, interface{}) error BindBody([]byte, interface{}) error
Besides, does the code above avoid print the bind uri error
log?
// ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request
// body into the context, and reuse when it is called again.
//
// NOTE: This method reads the body before binding. So you should use
// ShouldBindWith for better performance if you need to call only once.
func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (err error) {
var body []byte
if cb, ok := c.Get(BodyBytesKey); ok {
if cbb, ok := cb.([]byte); ok {
body = cbb
}
}
if body == nil {
body, err = ioutil.ReadAll(c.Request.Body)
if err != nil {
return err
}
c.Set(BodyBytesKey, body)
}
return bb.BindBody(body, obj)
}
This function will store the body at first calling, and it will get the store of body when you call it again.
Sorry for this error, I will try to research this issue.
Maybe you are right,
Maybe we need a
BindUrl
function ?
Or we can simply let BindUri
support query binding.
Query field is empty when checking the struct after binding URI.
There is a temporarily solution: Put field Name
and Query
into two different structs, you can bind them separately.
Maybe you are right,
Maybe we need a
BindUrl
function ?Or we can simply let
BindUri
support query binding. Query field is empty when checking the struct after binding URI.
BindUrl
may be a better solution because of backwards compatibility :)
Maybe you are right,
Maybe we need a
BindUrl
function ?Or we can simply let
BindUri
support query binding. Query field is empty when checking the struct after binding URI.
BindUrl
may be a better solution because of backwards compatibility :)
Any idea about it? i can try to contribute if the idea is accepted
What about creating a middleware to achieve this? and considering a third-party package like ggicci/httpin
I found that there is a method MapFormWithTag
in the binding package
for example
if you want to skip binding query and only bind uri and validate after bind uri
var req serializers.InternalGetMaxExpressCODAmountReq
if err := binding.MapFormWithTag(&req, c.Request.URL.Query(), "form"); err != nil {
log.Err(err).Ctx(c).Msg("Failed to parse request form")
response.Error(c, http.StatusBadRequest, err, translate.ErrorBadRequest)
return
}
if err := c.ShouldBindUri(&req); err != nil { // call bind only one time
log.Err(err).Ctx(c).Msg("Failed to parse request uri")
response.Error(c, http.StatusBadRequest, err, translate.ErrorBadRequest)
return
}
Now that gin doesn't support BindUrl(),we should think about other solutions.
Maybe we can define the struct better.
The first method define a struct contains uri struct and query struct.
The second method combound two struct.
I think it's clear and elegant. After all,we don't need to write annotations in one struct.