mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 21:32:11 +08:00
feat: add c.BindCookie and c.BindRequest
This commit is contained in:
parent
6ebb945bd7
commit
3607883289
79
README.md
79
README.md
@ -47,6 +47,8 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
|
||||
- [Bind Query String or Post Data](#bind-query-string-or-post-data)
|
||||
- [Bind Uri](#bind-uri)
|
||||
- [Bind Header](#bind-header)
|
||||
- [Bind Cookie](#bind-cookie)
|
||||
- [Bind Request](#bind-request)
|
||||
- [Bind HTML checkboxes](#bind-html-checkboxes)
|
||||
- [Multipart/Urlencoded binding](#multiparturlencoded-binding)
|
||||
- [XML, JSON, YAML and ProtoBuf rendering](#xml-json-yaml-and-protobuf-rendering)
|
||||
@ -663,10 +665,10 @@ Note that you need to set the corresponding binding tag on all fields you want t
|
||||
|
||||
Also, Gin provides two sets of methods for binding:
|
||||
- **Type** - Must bind
|
||||
- **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML`, `BindHeader`
|
||||
- **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML`, `BindHeader`, `BindCookie`, `BindRequest`
|
||||
- **Behavior** - These methods use `MustBindWith` under the hood. If there is a binding error, the request is aborted with `c.AbortWithError(400, err).SetType(ErrorTypeBind)`. This sets the response status code to 400 and the `Content-Type` header is set to `text/plain; charset=utf-8`. Note that if you try to set the response code after this, it will result in a warning `[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422`. If you wish to have greater control over the behavior, consider using the `ShouldBind` equivalent method.
|
||||
- **Type** - Should bind
|
||||
- **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML`, `ShouldBindHeader`
|
||||
- **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML`, `ShouldBindHeader`, `ShouldBindCookie`, `ShouldBindReqeust`
|
||||
- **Behavior** - These methods use `ShouldBindWith` under the hood. If there is a binding error, the error is returned and it is the developer's responsibility to handle the request and error appropriately.
|
||||
|
||||
When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`.
|
||||
@ -991,6 +993,79 @@ func main() {
|
||||
// output
|
||||
// {"Domain":"music","Rate":300}
|
||||
}
|
||||
```
|
||||
### Bind Cookie
|
||||
|
||||
see [Bind Request](#bind-request)
|
||||
|
||||
|
||||
### Bind Request
|
||||
|
||||
`c.BindRequest` and `c.ShouldBindRquest` can bind all wanted values into struct instance at once.
|
||||
Now,
|
||||
+ supports values from `form`, `uri`, `header`, `cookie`
|
||||
and request `req.Body`.
|
||||
+ `req.Body` decocder is decided by header `Content-Type` value, see more [request_test.go](./binding/binding_request_test.go#L40)
|
||||
|
||||
**example**
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Params struct {
|
||||
Name string `uri:"name"`
|
||||
Age int `form:"age,default=18"`
|
||||
Money int32 `form:"money" binding:"required"`
|
||||
Authorization string `cookie:"Authorization"`
|
||||
UserAgent string `header:"User-Agent"`
|
||||
Data *ParamBody `body:"body" mime:"json"`
|
||||
}
|
||||
|
||||
type ParamBody struct {
|
||||
Replicas *int32 `json:"replicas"`
|
||||
}
|
||||
|
||||
func NewParams() *Params {
|
||||
return &Params{
|
||||
Data: &ParamBody{},
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
|
||||
r.POST("/hello/:name", handler)
|
||||
_ = r.Run(":9881")
|
||||
|
||||
}
|
||||
|
||||
func handler(c *gin.Context) {
|
||||
var err error
|
||||
params := NewParams()
|
||||
|
||||
err = c.ShouldBindRequest(params)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, params)
|
||||
}
|
||||
|
||||
// ### POST test by RestClient of vscode extenstion
|
||||
// POST http://127.0.0.1:9881/hello/zhangsan?money=1000
|
||||
// Content-Type: application/json
|
||||
// Accept-Language: en-GB,en-US;q=0.8,en;q=0.6,zh-CN;q=0.4
|
||||
//
|
||||
// {
|
||||
// "replicas":5
|
||||
// }
|
||||
|
||||
```
|
||||
|
||||
### Bind HTML checkboxes
|
||||
|
@ -30,6 +30,7 @@ const (
|
||||
type Binding interface {
|
||||
Name() string
|
||||
Bind(*http.Request, interface{}) error
|
||||
BindOnly(*http.Request, interface{}) error
|
||||
}
|
||||
|
||||
// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
|
||||
@ -37,6 +38,7 @@ type Binding interface {
|
||||
type BindingBody interface {
|
||||
Binding
|
||||
BindBody([]byte, interface{}) error
|
||||
BindBodyOnly([]byte, interface{}) error
|
||||
}
|
||||
|
||||
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
||||
@ -83,6 +85,8 @@ var (
|
||||
YAML = yamlBinding{}
|
||||
Uri = uriBinding{}
|
||||
Header = headerBinding{}
|
||||
Request = requestBinding{}
|
||||
Cookie = cookieBinding{}
|
||||
)
|
||||
|
||||
// Default returns the appropriate Binding instance based on the HTTP method
|
||||
|
85
binding/binding_request_test.go
Normal file
85
binding/binding_request_test.go
Normal file
@ -0,0 +1,85 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type Params struct {
|
||||
Name string `uri:"name"`
|
||||
Age int `form:"age,default=18"`
|
||||
Money int32 `form:"money" binding:"required"`
|
||||
Authorization string `cookie:"Authorization"`
|
||||
UserAgent string `header:"User-Agent"`
|
||||
Data *ParamBody `body:"body"`
|
||||
}
|
||||
|
||||
type ParamBody struct {
|
||||
Replicas *int32 `json:"replicas"`
|
||||
}
|
||||
|
||||
func NewParams() *Params {
|
||||
return &Params{
|
||||
Data: &ParamBody{},
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindRequest(t *testing.T) {
|
||||
h := Request
|
||||
assert.Equal(t, "request", h.Name())
|
||||
|
||||
params := NewParams()
|
||||
|
||||
mocks := []struct {
|
||||
body string
|
||||
mime string
|
||||
method string
|
||||
}{
|
||||
{body: `replicas: 5`, mime: MIMEYAML, method: http.MethodPost},
|
||||
{body: `{"replicas": 5}`, mime: MIMEJSON, method: http.MethodPut},
|
||||
{body: `replicas=5`, mime: MIMEPOSTForm, method: http.MethodPatch},
|
||||
{body: `replicas=5`, mime: MIMEPOSTForm, method: http.MethodGet},
|
||||
{
|
||||
body: `<?xml version="1.0" encoding="UTF-8" ?><replicas>5</replicas>`,
|
||||
mime: MIMEXML2,
|
||||
method: http.MethodDelete,
|
||||
},
|
||||
{
|
||||
body: `<replicas>5</replicas>`,
|
||||
mime: MIMEXML,
|
||||
method: http.MethodDelete,
|
||||
},
|
||||
}
|
||||
|
||||
for _, mock := range mocks {
|
||||
|
||||
t.Run(mock.mime, func(t *testing.T) {
|
||||
req := requestWithBody(mock.method, "/hello/:name?money=1000", mock.body)
|
||||
mockUri := map[string][]string{
|
||||
"name": {"zhangsan"},
|
||||
}
|
||||
req.Header.Add("Content-Type", mock.mime)
|
||||
req.Header.Add("User-Agent", "go-client")
|
||||
req.AddCookie(
|
||||
&http.Cookie{Name: "Authorization", Value: "token 123123123"},
|
||||
)
|
||||
|
||||
err := h.Bind(params, req, mockUri)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "zhangsan", params.Name) // uri
|
||||
assert.Equal(t, 18, params.Age) // form,defualt
|
||||
assert.Equal(t, int32(1000), params.Money) // form,required
|
||||
assert.Equal(t, "token 123123123", params.Authorization) // cookie
|
||||
assert.Equal(t, "go-client", params.UserAgent) // header
|
||||
assert.Equal(t, int32(5), *params.Data.Replicas) // body,ptr
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -785,14 +785,14 @@ func TestUriBinding(t *testing.T) {
|
||||
var tag Tag
|
||||
m := make(map[string][]string)
|
||||
m["name"] = []string{"thinkerou"}
|
||||
assert.NoError(t, b.BindUri(m, &tag))
|
||||
assert.NoError(t, b.Bind(m, &tag))
|
||||
assert.Equal(t, "thinkerou", tag.Name)
|
||||
|
||||
type NotSupportStruct struct {
|
||||
Name map[string]interface{} `uri:"name"`
|
||||
}
|
||||
var not NotSupportStruct
|
||||
assert.Error(t, b.BindUri(m, ¬))
|
||||
assert.Error(t, b.Bind(m, ¬))
|
||||
assert.Equal(t, map[string]interface{}(nil), not.Name)
|
||||
}
|
||||
|
||||
@ -813,7 +813,7 @@ func TestUriInnerBinding(t *testing.T) {
|
||||
}
|
||||
|
||||
var tag Tag
|
||||
assert.NoError(t, Uri.BindUri(m, &tag))
|
||||
assert.NoError(t, Uri.Bind(m, &tag))
|
||||
assert.Equal(t, tag.Name, expectedName)
|
||||
assert.Equal(t, tag.S.Age, expectedAge)
|
||||
}
|
||||
|
27
binding/cookie.go
Normal file
27
binding/cookie.go
Normal file
@ -0,0 +1,27 @@
|
||||
package binding
|
||||
|
||||
import "net/http"
|
||||
|
||||
type cookieBinding struct{}
|
||||
|
||||
func (cookieBinding) Name() string {
|
||||
return "cookie"
|
||||
}
|
||||
|
||||
func (b cookieBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (cookieBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
cookies := req.Cookies()
|
||||
|
||||
form := make(map[string][]string, len(cookies))
|
||||
for i := 0; i < len(cookies); i++ {
|
||||
form[cookies[i].Name] = []string{cookies[i].Value}
|
||||
}
|
||||
|
||||
return mapFormByTag(obj, form, "cookie")
|
||||
}
|
@ -18,7 +18,14 @@ func (formBinding) Name() string {
|
||||
return "form"
|
||||
}
|
||||
|
||||
func (formBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
func (b formBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (b formBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -28,28 +35,42 @@ func (formBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := mapForm(obj, req.Form); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (formPostBinding) Name() string {
|
||||
return "form-urlencoded"
|
||||
}
|
||||
|
||||
func (formPostBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
func (b formPostBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (b formPostBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mapForm(obj, req.PostForm); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (formMultipartBinding) Name() string {
|
||||
return "multipart/form-data"
|
||||
}
|
||||
|
||||
func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
func (b formMultipartBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (b formMultipartBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
if err := req.ParseMultipartForm(defaultMemory); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -57,5 +78,5 @@ func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
return nil
|
||||
}
|
||||
|
@ -12,15 +12,19 @@ func (headerBinding) Name() string {
|
||||
return "header"
|
||||
}
|
||||
|
||||
func (headerBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
func (b headerBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
|
||||
if err := mapHeader(obj, req.Header); err != nil {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (headerBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
return mapHeader(obj, req.Header)
|
||||
}
|
||||
|
||||
func mapHeader(ptr interface{}, h map[string][]string) error {
|
||||
return mappingByPtr(ptr, headerSource(h), "header")
|
||||
}
|
||||
|
@ -30,14 +30,33 @@ func (jsonBinding) Name() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
func (b jsonBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
|
||||
}
|
||||
|
||||
func (b jsonBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
if req == nil || req.Body == nil {
|
||||
return errors.New("invalid request")
|
||||
}
|
||||
|
||||
// data, _ := ioutil.ReadAll(req.Body)
|
||||
// fmt.Printf("%s", data)
|
||||
|
||||
return decodeJSON(req.Body, obj)
|
||||
}
|
||||
|
||||
func (jsonBinding) BindBody(body []byte, obj interface{}) error {
|
||||
func (b jsonBinding) BindBody(body []byte, obj interface{}) error {
|
||||
if err := b.BindBodyOnly(body, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
func (b jsonBinding) BindBodyOnly(body []byte, obj interface{}) error {
|
||||
return decodeJSON(bytes.NewReader(body), obj)
|
||||
}
|
||||
|
||||
@ -52,5 +71,5 @@ func decodeJSON(r io.Reader, obj interface{}) error {
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
return nil
|
||||
}
|
||||
|
@ -21,18 +21,31 @@ func (msgpackBinding) Name() string {
|
||||
return "msgpack"
|
||||
}
|
||||
|
||||
func (msgpackBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
func (b msgpackBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (b msgpackBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
return decodeMsgPack(req.Body, obj)
|
||||
}
|
||||
|
||||
func (msgpackBinding) BindBody(body []byte, obj interface{}) error {
|
||||
func (b msgpackBinding) BindBody(body []byte, obj interface{}) error {
|
||||
if err := b.BindBodyOnly(body, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (b msgpackBinding) BindBodyOnly(body []byte, obj interface{}) error {
|
||||
return decodeMsgPack(bytes.NewReader(body), obj)
|
||||
}
|
||||
|
||||
func decodeMsgPack(r io.Reader, obj interface{}) error {
|
||||
cdc := new(codec.MsgpackHandle)
|
||||
if err := codec.NewDecoder(r, cdc).Decode(&obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
return codec.NewDecoder(r, cdc).Decode(&obj)
|
||||
}
|
||||
|
@ -18,14 +18,22 @@ func (protobufBinding) Name() string {
|
||||
}
|
||||
|
||||
func (b protobufBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
return b.BindOnly(req, obj)
|
||||
}
|
||||
|
||||
func (b protobufBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
buf, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.BindBody(buf, obj)
|
||||
return b.BindBodyOnly(buf, obj)
|
||||
}
|
||||
|
||||
func (protobufBinding) BindBody(body []byte, obj interface{}) error {
|
||||
func (b protobufBinding) BindBody(body []byte, obj interface{}) error {
|
||||
return b.BindBodyOnly(body, obj)
|
||||
}
|
||||
|
||||
func (protobufBinding) BindBodyOnly(body []byte, obj interface{}) error {
|
||||
if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -12,10 +12,18 @@ func (queryBinding) Name() string {
|
||||
return "query"
|
||||
}
|
||||
|
||||
func (queryBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
func (b queryBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (queryBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
values := req.URL.Query()
|
||||
if err := mapForm(obj, values); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
return nil
|
||||
}
|
||||
|
75
binding/request.go
Normal file
75
binding/request.go
Normal file
@ -0,0 +1,75 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type requestBinding struct{}
|
||||
|
||||
func (requestBinding) Name() string {
|
||||
return "request"
|
||||
}
|
||||
|
||||
func (b requestBinding) Bind(obj interface{}, req *http.Request, form map[string][]string) error {
|
||||
if err := b.BindOnly(obj, req, form); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (b requestBinding) BindOnly(obj interface{}, req *http.Request, uriMap map[string][]string) error {
|
||||
|
||||
if err := Uri.BindOnly(uriMap, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
binders := []interface{}{Header, Query, Cookie}
|
||||
for _, binder := range binders {
|
||||
if b, ok := binder.(Binding); ok {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// body decode
|
||||
bodyPtr := reflectx(obj)
|
||||
|
||||
// default json
|
||||
contentType := req.Header.Get("Content-Type")
|
||||
if contentType == "" {
|
||||
contentType = MIMEJSON
|
||||
}
|
||||
bb := Default(req.Method, contentType)
|
||||
return bb.BindOnly(req, bodyPtr)
|
||||
|
||||
}
|
||||
|
||||
func reflectx(obj interface{}) interface{} {
|
||||
|
||||
// pre-check obj
|
||||
rv := reflect.ValueOf(obj)
|
||||
rv = reflect.Indirect(rv)
|
||||
if rv.Kind() != reflect.Struct {
|
||||
return nil
|
||||
}
|
||||
|
||||
typ := rv.Type()
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
tf := typ.Field(i)
|
||||
vf := rv.Field(i)
|
||||
_, ok := tf.Tag.Lookup("body")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// find body struct
|
||||
if vf.Kind() == reflect.Ptr && vf.Elem().Kind() == reflect.Struct {
|
||||
return vf.Interface()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -10,9 +10,13 @@ func (uriBinding) Name() string {
|
||||
return "uri"
|
||||
}
|
||||
|
||||
func (uriBinding) BindUri(m map[string][]string, obj interface{}) error {
|
||||
func (uriBinding) Bind(m map[string][]string, obj interface{}) error {
|
||||
if err := mapUri(obj, m); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (uriBinding) BindOnly(m map[string][]string, obj interface{}) error {
|
||||
return mapUri(obj, m)
|
||||
}
|
||||
|
@ -18,16 +18,35 @@ func (xmlBinding) Name() string {
|
||||
}
|
||||
|
||||
func (xmlBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
err := decodeXML(req.Body, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (xmlBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
return decodeXML(req.Body, obj)
|
||||
}
|
||||
|
||||
func (xmlBinding) BindBody(body []byte, obj interface{}) error {
|
||||
func (b xmlBinding) BindBody(body []byte, obj interface{}) error {
|
||||
if err := b.BindBodyOnly(body, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (xmlBinding) BindBodyOnly(body []byte, obj interface{}) error {
|
||||
return decodeXML(bytes.NewReader(body), obj)
|
||||
}
|
||||
|
||||
func decodeXML(r io.Reader, obj interface{}) error {
|
||||
decoder := xml.NewDecoder(r)
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -18,18 +18,31 @@ func (yamlBinding) Name() string {
|
||||
return "yaml"
|
||||
}
|
||||
|
||||
func (yamlBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
func (b yamlBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (yamlBinding) BindOnly(req *http.Request, obj interface{}) error {
|
||||
return decodeYAML(req.Body, obj)
|
||||
}
|
||||
|
||||
func (yamlBinding) BindBody(body []byte, obj interface{}) error {
|
||||
func (b yamlBinding) BindBody(body []byte, obj interface{}) error {
|
||||
if err := b.BindBodyOnly(body, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (yamlBinding) BindBodyOnly(body []byte, obj interface{}) error {
|
||||
return decodeYAML(bytes.NewReader(body), obj)
|
||||
}
|
||||
|
||||
func decodeYAML(r io.Reader, obj interface{}) error {
|
||||
decoder := yaml.NewDecoder(r)
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
return decoder.Decode(obj)
|
||||
}
|
||||
|
50
context.go
50
context.go
@ -631,6 +631,11 @@ func (c *Context) BindHeader(obj interface{}) error {
|
||||
return c.MustBindWith(obj, binding.Header)
|
||||
}
|
||||
|
||||
// BindCookie is a shortcut for c.MustBindWith(obj, binding.Cookie).
|
||||
func (c *Context) BindCookie(obj interface{}) error {
|
||||
return c.MustBindWith(obj, binding.Cookie)
|
||||
}
|
||||
|
||||
// BindUri binds the passed struct pointer using binding.Uri.
|
||||
// It will abort the request with HTTP 400 if any error occurs.
|
||||
func (c *Context) BindUri(obj interface{}) error {
|
||||
@ -641,6 +646,16 @@ func (c *Context) BindUri(obj interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// BindRequest binds the passed struct pointer using binding.Request.
|
||||
// It will abort the request with HTTP 400 if any error occurs.
|
||||
func (c *Context) BindRequest(obj interface{}) error {
|
||||
if err := c.ShouldBindRequest(obj); err != nil {
|
||||
c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MustBindWith binds the passed struct pointer using the specified binding engine.
|
||||
// It will abort the request with HTTP 400 if any error occurs.
|
||||
// See the binding package.
|
||||
@ -690,13 +705,46 @@ func (c *Context) ShouldBindHeader(obj interface{}) error {
|
||||
return c.ShouldBindWith(obj, binding.Header)
|
||||
}
|
||||
|
||||
// ShouldBindCookie is a shortcut for c.ShouldBindWith(obj, binding.Cookie).
|
||||
func (c *Context) ShouldBindCookie(obj interface{}) error {
|
||||
return c.ShouldBindWith(obj, binding.Cookie)
|
||||
}
|
||||
|
||||
// ShouldBindUri binds the passed struct pointer using the specified binding engine.
|
||||
func (c *Context) ShouldBindUri(obj interface{}) error {
|
||||
m := make(map[string][]string)
|
||||
for _, v := range c.Params {
|
||||
m[v.Key] = []string{v.Value}
|
||||
}
|
||||
return binding.Uri.BindUri(m, obj)
|
||||
return binding.Uri.Bind(m, obj)
|
||||
}
|
||||
|
||||
// ShouldBindRequest binds the passed struct pointer using the specified binding engine.
|
||||
// including
|
||||
// `uri`,
|
||||
// `query`
|
||||
// `header` and
|
||||
// `body data` with tag `body:"body"`
|
||||
// and it's decoder is decided by header `Content-Type` value
|
||||
//
|
||||
// type Params struct {
|
||||
// Name string `uri:"name"`
|
||||
// Age string `form:"age" default:"100"`
|
||||
// Money string `form:"money" binding:"required"`
|
||||
// Authorization string `cookie:"Authorization"`
|
||||
// UserAgent string `header:"User-Agent"`
|
||||
// Data *ParamBody `body:"body" mime:"json"`
|
||||
// }
|
||||
// type ParamBody struct {
|
||||
// Replicas *int32 `json:"replicas"`
|
||||
// }
|
||||
func (c *Context) ShouldBindRequest(obj interface{}) error {
|
||||
params := make(map[string][]string)
|
||||
for _, v := range c.Params {
|
||||
params[v.Key] = []string{v.Value}
|
||||
}
|
||||
|
||||
return binding.Request.Bind(obj, c.Request, params)
|
||||
}
|
||||
|
||||
// ShouldBindWith binds the passed struct pointer using the specified binding engine.
|
||||
|
Loading…
x
Reference in New Issue
Block a user