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 == GET || req.Method == DELETE {
35 if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
36 return NewHTTPError(http.StatusBadRequest, err.Error())
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, offset=%v", ute.Type, ute.Value, ute.Offset))
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()))
51 return NewHTTPError(http.StatusBadRequest, err.Error())
54 case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
55 if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
56 if ute, ok := err.(*xml.UnsupportedTypeError); ok {
57 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error()))
58 } else if se, ok := err.(*xml.SyntaxError); ok {
59 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error()))
61 return NewHTTPError(http.StatusBadRequest, err.Error())
64 case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
65 params, err := c.FormParams()
67 return NewHTTPError(http.StatusBadRequest, err.Error())
69 if err = b.bindData(i, params, "form"); err != nil {
70 return NewHTTPError(http.StatusBadRequest, err.Error())
73 return ErrUnsupportedMediaType
78 func (b *DefaultBinder) bindData(ptr interface{}, data map[string][]string, tag string) error {
79 typ := reflect.TypeOf(ptr).Elem()
80 val := reflect.ValueOf(ptr).Elem()
82 if typ.Kind() != reflect.Struct {
83 return errors.New("binding element must be a struct")
86 for i := 0; i < typ.NumField(); i++ {
87 typeField := typ.Field(i)
88 structField := val.Field(i)
89 if !structField.CanSet() {
92 structFieldKind := structField.Kind()
93 inputFieldName := typeField.Tag.Get(tag)
95 if inputFieldName == "" {
96 inputFieldName = typeField.Name
97 // If tag is nil, we inspect if the field is a struct.
98 if _, ok := bindUnmarshaler(structField); !ok && structFieldKind == reflect.Struct {
99 err := b.bindData(structField.Addr().Interface(), data, tag)
106 inputValue, exists := data[inputFieldName]
111 // Call this first, in case we're dealing with an alias to an array type
112 if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
119 numElems := len(inputValue)
120 if structFieldKind == reflect.Slice && numElems > 0 {
121 sliceOf := structField.Type().Elem().Kind()
122 slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
123 for j := 0; j < numElems; j++ {
124 if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
128 val.Field(i).Set(slice)
130 if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
138 func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
139 // But also call it here, in case we're dealing with an array of BindUnmarshalers
140 if ok, err := unmarshalField(valueKind, val, structField); ok {
146 return setWithProperType(structField.Elem().Kind(), val, structField.Elem())
148 return setIntField(val, 0, structField)
150 return setIntField(val, 8, structField)
152 return setIntField(val, 16, structField)
154 return setIntField(val, 32, structField)
156 return setIntField(val, 64, structField)
158 return setUintField(val, 0, structField)
160 return setUintField(val, 8, structField)
162 return setUintField(val, 16, structField)
164 return setUintField(val, 32, structField)
166 return setUintField(val, 64, structField)
168 return setBoolField(val, structField)
169 case reflect.Float32:
170 return setFloatField(val, 32, structField)
171 case reflect.Float64:
172 return setFloatField(val, 64, structField)
174 structField.SetString(val)
176 return errors.New("unknown type")
181 func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
184 return unmarshalFieldPtr(val, field)
186 return unmarshalFieldNonPtr(val, field)
190 // bindUnmarshaler attempts to unmarshal a reflect.Value into a BindUnmarshaler
191 func bindUnmarshaler(field reflect.Value) (BindUnmarshaler, bool) {
192 ptr := reflect.New(field.Type())
193 if ptr.CanInterface() {
194 iface := ptr.Interface()
195 if unmarshaler, ok := iface.(BindUnmarshaler); ok {
196 return unmarshaler, ok
202 func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
203 if unmarshaler, ok := bindUnmarshaler(field); ok {
204 err := unmarshaler.UnmarshalParam(value)
205 field.Set(reflect.ValueOf(unmarshaler).Elem())
211 func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) {
213 // Initialize the pointer to a nil value
214 field.Set(reflect.New(field.Type().Elem()))
216 return unmarshalFieldNonPtr(value, field.Elem())
219 func setIntField(value string, bitSize int, field reflect.Value) error {
223 intVal, err := strconv.ParseInt(value, 10, bitSize)
230 func setUintField(value string, bitSize int, field reflect.Value) error {
234 uintVal, err := strconv.ParseUint(value, 10, bitSize)
236 field.SetUint(uintVal)
241 func setBoolField(value string, field reflect.Value) error {
245 boolVal, err := strconv.ParseBool(value)
247 field.SetBool(boolVal)
252 func setFloatField(value string, bitSize int, field reflect.Value) error {
256 floatVal, err := strconv.ParseFloat(value, bitSize)
258 field.SetFloat(floatVal)