gin/binding/request.go

80 lines
1.4 KiB
Go

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
bodyObj := extractBody(obj)
if bodyObj == nil {
return nil
}
// default json
contentType := req.Header.Get("Content-Type")
if contentType == "" {
contentType = MIMEJSON
}
bb := Default(req.Method, contentType)
return bb.BindOnly(req, bodyObj)
}
// extractBody return body object
func extractBody(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 reflect.Indirect(vf).Kind() == reflect.Struct {
return vf.Addr().Interface()
}
}
return nil
}