Description
I'm trying to bind JSON and a URI in one request but havn't found out how to yet.
Here's my struct:
type ResetPassword struct {
Code string `uri:"code" binding:"required"`
Password string `json:"password" binding:"required,min=6,max=20"`
}
I'm using c.Bind()
:
func verifyPasswordReset(c *gin.Context) {
var data ResetPassword
if err := c.Bind(&data); err != nil {
c.JSON(400, gin.H{"error": err})
return
}
fmt.Printf("%+v\n", data)
c.JSON(http.StatusOK, data)
}
When I make this request it says the code is required:
curl -H "content-type:application/json" -d '{"password":"hunter15"}' "localhost:8080/user/password_reset/jksakhdkh" Sun Mar 24 14:29:27 2019
{"error":{".Code":{"FieldNamespace":".Code","NameNamespace":"Code","Field":"Code","Name":"Code","Tag":"required","ActualTag":"required","Kind":24,"Type":{},"Param":"","Value":""}}}
I found a related issue #811 but it wasn't actually solved before being closed.
Comment From: thinkerou
you should split bind uri and json to two struct.
Comment From: montanaflynn
@thinkerou ok, I split it into two structs and used the respective binds:
if err := c.ShouldBindUri(&dataURI); err != nil {
c.JSON(400, gin.H{"error": err})
return
}
if err := c.ShouldBindJSON(&dataJSON); err != nil {
c.JSON(400, gin.H{"error": err})
return
}
That works fine and removes my workaround of using c.Params.ByName("code")
, thanks!
Comment From: m430
@thinkerou Why not use the uri and form tag together? I think it would be convenient.
Comment From: invisibleDesigner
no, I want to use it in one struct
Comment From: chengr4
At 2023, we still should split it into two structs?
Comment From: TaylorDurden
At 2023, we still should split it into two structs? Here is a example:
type updateAccountRequest struct {
ID int64 `uri:"id" binding:"required,min=1"`
Balance int64 `json:"balance"`
}
func (server *Server) updateAccountHandler(ctx *gin.Context) {
var req updateAccountRequest
if err := ctx.ShouldBindUri(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
arg := db.UpdateAccountParams{
ID: req.ID,
Balance: req.Balance,
}
updatedAccount, err := server.store.UpdateAccount(ctx, arg)
if err != nil {
if err == sql.ErrNoRows {
ctx.JSON(http.StatusNotFound, errorResponse(err))
return
}
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
ctx.JSON(http.StatusOK, updatedAccount)
}
Comment From: QingShan-Xu
Balance int64
json:"balance"
If you set Balance int64 json:"balance" binding:"required"
, it will still fail because shoudBindUri binds json:"balance" but there is no balance in the uri.