* Add interface to read body bytes in binding * Add BindingBody implementation for some binding * Fix to use `BindBodyBytesKey` for key * Revert "Fix to use `BindBodyBytesKey` for key" This reverts commit 2c82901ceab6ae53730a3cfcd9839bee11a08f13. * Use private-like key for body bytes * Add tests for BindingBody & ShouldBindBodyWith * Add note for README * Remove redundant space between sentences
This commit is contained in:
committed by
Bo-Yi Wu
parent
6e09ef03b0
commit
995fa8e9ce
59
README.md
59
README.md
@ -52,6 +52,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
|
||||
- [Graceful restart or stop](#graceful-restart-or-stop)
|
||||
- [Build a single binary with templates](#build-a-single-binary-with-templates)
|
||||
- [Bind form-data request with custom struct](#bind-form-data-request-with-custom-struct)
|
||||
- [Try to bind body into different structs](#try-to-bind-body-into-different-structs)
|
||||
- [Testing](#testing)
|
||||
- [Users](#users--)
|
||||
|
||||
@ -1554,6 +1555,64 @@ type StructZ struct {
|
||||
|
||||
In a word, only support nested custom struct which have no `form` now.
|
||||
|
||||
### Try to bind body into different structs
|
||||
|
||||
The normal methods for binding request body consumes `c.Request.Body` and they
|
||||
cannot be called multiple times.
|
||||
|
||||
```go
|
||||
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{}
|
||||
// This c.ShouldBind consumes c.Request.Body and it cannot be reused.
|
||||
if errA := c.ShouldBind(&objA); errA == nil {
|
||||
c.String(http.StatusOK, `the body should be formA`)
|
||||
// Always an error is occurred by this because c.Request.Body is EOF now.
|
||||
} else if errB := c.ShouldBind(&objB); errB == nil {
|
||||
c.String(http.StatusOK, `the body should be formB`)
|
||||
} else {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For this, you can use `c.ShouldBindBodyWith`.
|
||||
|
||||
```go
|
||||
func SomeHandler(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.String(http.StatusOK, `the body should be formA`)
|
||||
// At this time, it reuses body stored in the context.
|
||||
} else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {
|
||||
c.String(http.StatusOK, `the body should be formB JSON`)
|
||||
// And it can accepts other formats
|
||||
} else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil {
|
||||
c.String(http.StatusOK, `the body should be formB XML`)
|
||||
} else {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* `c.ShouldBindBodyWith` stores body into the context before binding. This has
|
||||
a slight impact to performance, so you should not use this method if you are
|
||||
enough to call binding at once.
|
||||
* This feature is only needed for some formats -- `JSON`, `XML`, `MsgPack`,
|
||||
`ProtoBuf`. For other formats, `Query`, `Form`, `FormPost`, `FormMultipart`,
|
||||
can be called by `c.ShouldBind()` multiple times without any damage to
|
||||
performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)).
|
||||
|
||||
## Testing
|
||||
|
||||
The `net/http/httptest` package is preferable way for HTTP testing.
|
||||
|
Reference in New Issue
Block a user