15 // Binder is the interface that wraps the Bind method.
17 Bind(i interface{}, c Context) error
20 // DefaultBinder is the default implementation of the Binder interface.
21 DefaultBinder struct{}
23 // BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
24 BindUnmarshaler interface {
25 // UnmarshalParam decodes and assigns a value from an form or query param.
26 UnmarshalParam(param string) error
30 // Bind implements the `Binder#Bind` function.
31 func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
33 if req.ContentLength == 0 {
34 if req.Method == http.MethodGet || req.Method == http.MethodDelete {
35 if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
36 return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
40 return NewHTTPError(http.StatusBadRequest, "Request body can't be empty")
42 ctype := req.Header.Get(HeaderContentType)
44 case strings.HasPrefix(ctype, MIMEApplicationJSON):
45 if err = json.NewDecoder(req.Body).Decode(i); err != nil {
46 if ute, ok := err.(*json.UnmarshalTypeError); ok {
47 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset)).SetInternal(err)
48 } else if se, ok := err.(*json.SyntaxError); ok {
49 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error())).SetInternal(err)
51 return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
53 return NewHTTPError(http.StatusBadRequest, err.Error())
55 case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
56 if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
57 if ute, ok := err.(*xml.UnsupportedTypeError); ok {
58 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error())).SetInternal(err)
59 } else if se, ok := err.(*xml.SyntaxError); ok {
60 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error())).SetInternal(err)
62 return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
64 return NewHTTPError(http.StatusBadRequest, err.Error())
66 case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
67 params, err := c.FormParams()
69 return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
71 if err = b.bindData(i, params, "form"); err != nil {
72 return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
75 return ErrUnsupportedMediaType
80 func (b *DefaultBinder) bindData(ptr interface{}, data map[string][]string, tag string) error {
81 typ := reflect.TypeOf(ptr).Elem()
82 val := reflect.ValueOf(ptr).Elem()
84 if typ.Kind() != reflect.Struct {
85 return errors.New("binding element must be a struct")
88 for i := 0; i < typ.NumField(); i++ {
89 typeField := typ.Field(i)
90 structField := val.Field(i)
91 if !structField.CanSet() {
94 structFieldKind := structField.Kind()
95 inputFieldName := typeField.Tag.Get(tag)
97 if inputFieldName == "" {
98 inputFieldName = typeField.Name
99 // If tag is nil, we inspect if the field is a struct.
100 if _, ok := bindUnmarshaler(structField); !ok && structFieldKind == reflect.Struct {
101 if err := b.bindData(structField.Addr().Interface(), data, tag); err != nil {
108 inputValue, exists := data[inputFieldName]
110 // Go json.Unmarshal supports case insensitive binding. However the
111 // url params are bound case sensitive which is inconsistent. To
112 // fix this we must check all of the map values in a
113 // case-insensitive search.
114 inputFieldName = strings.ToLower(inputFieldName)
115 for k, v := range data {
116 if strings.ToLower(k) == inputFieldName {
128 // Call this first, in case we're dealing with an alias to an array type
129 if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
136 numElems := len(inputValue)
137 if structFieldKind == reflect.Slice && numElems > 0 {
138 sliceOf := structField.Type().Elem().Kind()
139 slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
140 for j := 0; j < numElems; j++ {
141 if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
145 val.Field(i).Set(slice)
146 } else if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
154 func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
155 // But also call it here, in case we're dealing with an array of BindUnmarshalers
156 if ok, err := unmarshalField(valueKind, val, structField); ok {
162 return setWithProperType(structField.Elem().Kind(), val, structField.Elem())
164 return setIntField(val, 0, structField)
166 return setIntField(val, 8, structField)
168 return setIntField(val, 16, structField)
170 return setIntField(val, 32, structField)
172 return setIntField(val, 64, structField)
174 return setUintField(val, 0, structField)
176 return setUintField(val, 8, structField)
178 return setUintField(val, 16, structField)
180 return setUintField(val, 32, structField)
182 return setUintField(val, 64, structField)
184 return setBoolField(val, structField)
185 case reflect.Float32:
186 return setFloatField(val, 32, structField)
187 case reflect.Float64:
188 return setFloatField(val, 64, structField)
190 structField.SetString(val)
192 return errors.New("unknown type")
197 func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
200 return unmarshalFieldPtr(val, field)
202 return unmarshalFieldNonPtr(val, field)
206 // bindUnmarshaler attempts to unmarshal a reflect.Value into a BindUnmarshaler
207 func bindUnmarshaler(field reflect.Value) (BindUnmarshaler, bool) {
208 ptr := reflect.New(field.Type())
209 if ptr.CanInterface() {
210 iface := ptr.Interface()
211 if unmarshaler, ok := iface.(BindUnmarshaler); ok {
212 return unmarshaler, ok
218 func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
219 if unmarshaler, ok := bindUnmarshaler(field); ok {
220 err := unmarshaler.UnmarshalParam(value)
221 field.Set(reflect.ValueOf(unmarshaler).Elem())
227 func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) {
229 // Initialize the pointer to a nil value
230 field.Set(reflect.New(field.Type().Elem()))
232 return unmarshalFieldNonPtr(value, field.Elem())
235 func setIntField(value string, bitSize int, field reflect.Value) error {
239 intVal, err := strconv.ParseInt(value, 10, bitSize)
246 func setUintField(value string, bitSize int, field reflect.Value) error {
250 uintVal, err := strconv.ParseUint(value, 10, bitSize)
252 field.SetUint(uintVal)
257 func setBoolField(value string, field reflect.Value) error {
261 boolVal, err := strconv.ParseBool(value)
263 field.SetBool(boolVal)
268 func setFloatField(value string, bitSize int, field reflect.Value) error {
272 floatVal, err := strconv.ParseFloat(value, bitSize)
274 field.SetFloat(floatVal)