body를 다른 구조체에 바인드 하기
일반적인 body 바인딩 메소드는 c.Request.Body
를 소모합니다.
따라서 이러한 메소드들은 여러번 호출할 수 없습니다.
type formA struct {
Foo string `json:"foo" xml:"foo" binding:"required"`
}
type formB struct {
Bar string `json:"bar" xml:"bar" binding:"required"`
}
func SomeHandler(c *gin.Context) {
objA := formA{}
objB := formB{}
// 아래의 c.ShouldBind는 c.Request.Body를 소모하며, 재이용이 불가능합니다.
if errA := c.ShouldBind(&objA); errA == nil {
c.String(http.StatusOK, `the body should be formA`)
// c.Request.Body가 EOF 이므로 에러가 발생합니다.
} else if errB := c.ShouldBind(&objB); errB == nil {
c.String(http.StatusOK, `the body should be formB`)
} else {
...
}
}
이를 위해 c.ShouldBindBodyWith
를 사용하여 해결 할 수 있습니다.
func SomeHandler(c *gin.Context) {
objA := formA{}
objB := formB{}
// c.Request.Body를 읽고 context에 결과를 저장합니다.
if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil {
c.String(http.StatusOK, `the body should be formA`)
// context에 저장된 body를 읽어 재이용 합니다.
} else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {
c.String(http.StatusOK, `the body should be formB JSON`)
// 다른 형식을 사용할 수도 있습니다.
} else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil {
c.String(http.StatusOK, `the body should be formB XML`)
} else {
...
}
}
c.ShouldBindBodyWith
는 바인딩 전에 context에 body를 저장합니다. 이것은 성능에 약간의 영향을 미치기 때문에 한번의 바인딩으로 충분하다면, 이 메소드를 사용하지 않는 것이 좋습니다.- 이 기능은
JSON
,XML
,MsgPack
,ProtoBuf
형식에만 필요합니다.Query
,Form
,FormPost
,FormMultipart
와 같은 다른 형식은 성능에 영향을 주지 않고c.ShouldBind()
에 의해 여러번 호출 될 수 있습니다. (이슈 참고#1341).