컨텐츠로 건너뛰기

바디를 다른 구조체에 바인딩 시도

c.ShouldBind과 같은 표준 바인딩 메서드는 io.ReadCloserc.Request.Body를 소비합니다. 한 번 읽으면 다시 읽을 수 없습니다. 이는 동일한 요청에서 다른 구조체 형태로 c.ShouldBind를 여러 번 호출할 수 없다는 것을 의미합니다.

이 문제를 해결하려면 c.ShouldBindBodyWith를 사용하세요. 바디를 한 번 읽고 컨텍스트에 저장하여 이후 바인딩에서 캐시된 바디를 재사용할 수 있습니다.

package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
type formA struct {
Foo string `json:"foo" xml:"foo" binding:"required"`
}
type formB struct {
Bar string `json:"bar" xml:"bar" binding:"required"`
}
func main() {
router := gin.Default()
router.POST("/bind", func(c *gin.Context) {
objA := formA{}
objB := formB{}
// This reads c.Request.Body and stores the result into the context.
if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil {
c.JSON(http.StatusOK, gin.H{"message": "matched formA", "foo": objA.Foo})
return
}
// At this time, it reuses body stored in the context.
if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {
c.JSON(http.StatusOK, gin.H{"message": "matched formB", "bar": objB.Bar})
return
}
c.JSON(http.StatusBadRequest, gin.H{"error": "request body did not match any known format"})
})
router.Run(":8080")
}

테스트

Terminal window
# Body matches formA
curl -X POST http://localhost:8080/bind \
-H "Content-Type: application/json" \
-d '{"foo":"hello"}'
# Output: {"foo":"hello","message":"matched formA"}
# Body matches formB
curl -X POST http://localhost:8080/bind \
-H "Content-Type: application/json" \
-d '{"bar":"world"}'
# Output: {"bar":"world","message":"matched formB"}

참고