gin icon indicating copy to clipboard operation
gin copied to clipboard

how to binding param and json

Open lun3322 opened this issue 5 years ago • 17 comments

How to reproduce

package main

import (
	"github.com/gin-gonic/gin"
)

type UserRequest struct {
	Id       int    `uri:"id"`
	Nickname string `json:"nickname"`
	Mobile   string `json:"mobile"`
	Email    string `json:"email"`
}

func main() {
	g := gin.Default()
	g.GET("/user/:id", func(c *gin.Context) {
		// how to do?
	})
	g.Run(":9000")
}
curl -v -X POST \
  http://localhost:8080/user/12\
  -H 'content-type: application/json' \
  -d '{"nickname": "nickname1","mobile": "133232323232","email": "[email protected]"

lun3322 avatar Oct 20 '20 15:10 lun3322

Bind twice.

	g.POST("/user/:id", func(c *gin.Context) {
		var u UserRequest 

		if err := c.ShouldBindUri(&u); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		if err := c.ShouldBindJSON(&u); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		fmt.Printf("id: %d nickname: %s mobile: %s email: %s\n", u.Id, u.Nickname, u.Mobile, u.Email)

		c.JSON(http.StatusNoContent, nil)
	})

This is the related issue. https://github.com/gin-gonic/gin/issues/1824

Please tell me if there is another good way!

Doarakko avatar Oct 20 '20 16:10 Doarakko

I also want to know if there is another way

lun3322 avatar Oct 21 '20 01:10 lun3322

Can't you do something like

u.ID = c.Param("id")?

agmadt avatar Oct 21 '20 23:10 agmadt

It seems that it is not possible to bind successfully by calling the API once.

lun3322 avatar Oct 22 '20 01:10 lun3322

Bind twice.

	g.POST("/user/:id", func(c *gin.Context) {
		var u UserRequest 

		if err := c.ShouldBindUri(&u); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		if err := c.ShouldBindJSON(&u); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		fmt.Printf("id: %d nickname: %s mobile: %s email: %s\n", u.Id, u.Nickname, u.Mobile, u.Email)

		c.JSON(http.StatusNoContent, nil)
	})

This is the related issue. #1824

Please tell me if there is another good way!

Only work with non-required fields. Is there anyway with required fields?

type UpdateRequest struct {
    ID   uint64 `uri:"id" binding:"required"`
    Data struct {
        Name string `json:"name" binding:"required"`
        Slug string `json:"slug" binding:"required"`
    }
}

tunhuit avatar Jun 23 '21 05:06 tunhuit

As mentioned above, the workaround (bind twice) doesn't work with required fields.

NicklasWallgren avatar Apr 28 '22 10:04 NicklasWallgren

+1 on this. Any updates or workarounds for required fields?

jlaneve avatar May 14 '22 23:05 jlaneve

+1

uedayuji avatar Aug 23 '22 04:08 uedayuji

+1

tiredsosha avatar Sep 26 '22 11:09 tiredsosha

+1

murfidaz avatar Nov 24 '22 03:11 murfidaz

+1

neopoleones avatar Dec 20 '22 13:12 neopoleones

+1

alahaiyo avatar Jan 03 '23 02:01 alahaiyo

+1

zhouguangming avatar Jun 06 '23 04:06 zhouguangming

+1

c5ms avatar Jun 25 '23 05:06 c5ms

ok here is an example :


// here ,we can use this struct in get method again.
type UserGetRequest struct {
	Id models.Id `uri:"id" binding:"required"`
}

type UserUpdateRequest struct {
	Nickname string `json:"nickname" `
}



func UserGet(context *gin.Context, domain *domains.Context) {
	var (
		locator = new(UserGetRequest)
	)

	if err = context.BindUri(locator); err != nil {
		return
	}

	if user, err = upms.UserGet(domain, locator.Id); err == nil {
		 ... 
	}
	return
}


func UserUpdate(context *gin.Context)  {
	var (
                locator  = new(UserGetRequest)
		request = new(UserUpdateRequest)
	)

	if err = context.BindUri(&params); err != nil {
		return
	}

	if err = context.BindJSON(&request); err != nil {
		return
	}

	var action = upms.UserUpdateAction{
		Nickname: request.Nickname,
	}

	if user, err = upms.UserUpdate(domain, locator.Id, action); err == nil {
		.....
	}

	return
}

c5ms avatar Jul 14 '23 09:07 c5ms

Is it a good idea to support something like requried_in=json, required_in=uri? If it makes sense, I would like to create a pr.

abawchen avatar Jul 14 '23 09:07 abawchen

This worked for me:

ok here is an example :

// here ,we can use this struct in get method again.
type UserGetRequest struct {
	Id models.Id `uri:"id" binding:"required"`
}

type UserUpdateRequest struct {
	Nickname string `json:"nickname" `
}


func UserUpdate(context *gin.Context)  {
	var (
                locator  = new(UserGetRequest)
		request = new(UserUpdateRequest)
	)

	if err = context.BindUri(&params); err != nil {
		return
	}

	if err = context.BindJSON(&request); err != nil {
		return
	}

	var action = upms.UserUpdateAction{
		Nickname: request.Nickname,
	}

	if user, err = upms.UserUpdate(domain, locator.Id, action); err == nil {
		.....
	}

	return
}

carlosmaranje avatar Oct 06 '23 18:10 carlosmaranje