Skip to content

Commit c57fcb3

Browse files
authored
Default binder can use UnmarshalParams(params []string) error interface to bind multiple input values at one go. (#2607)
1 parent a3b0ba2 commit c57fcb3

File tree

2 files changed

+301
-65
lines changed

2 files changed

+301
-65
lines changed

bind.go

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ type BindUnmarshaler interface {
3030
UnmarshalParam(param string) error
3131
}
3232

33+
// bindMultipleUnmarshaler is used by binder to unmarshal multiple values from request at once to
34+
// type implementing this interface. For example request could have multiple query fields `?a=1&a=2&b=test` in that case
35+
// for `a` following slice `["1", "2"] will be passed to unmarshaller.
36+
type bindMultipleUnmarshaler interface {
37+
UnmarshalParams(params []string) error
38+
}
39+
3340
// BindPathParams binds path params to bindable object
3441
func (b *DefaultBinder) BindPathParams(c Context, i interface{}) error {
3542
names := c.ParamNames()
@@ -217,8 +224,15 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
217224
continue
218225
}
219226

227+
if ok, err := unmarshalInputsToField(typeField.Type.Kind(), inputValue, structField); ok {
228+
if err != nil {
229+
return err
230+
}
231+
continue
232+
}
233+
220234
// Call this first, in case we're dealing with an alias to an array type
221-
if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
235+
if ok, err := unmarshalInputToField(typeField.Type.Kind(), inputValue[0], structField); ok {
222236
if err != nil {
223237
return err
224238
}
@@ -245,7 +259,7 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
245259

246260
func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
247261
// But also call it here, in case we're dealing with an array of BindUnmarshalers
248-
if ok, err := unmarshalField(valueKind, val, structField); ok {
262+
if ok, err := unmarshalInputToField(valueKind, val, structField); ok {
249263
return err
250264
}
251265

@@ -286,33 +300,39 @@ func setWithProperType(valueKind reflect.Kind, val string, structField reflect.V
286300
return nil
287301
}
288302

289-
func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
290-
switch valueKind {
291-
case reflect.Ptr:
292-
return unmarshalFieldPtr(val, field)
293-
default:
294-
return unmarshalFieldNonPtr(val, field)
303+
func unmarshalInputsToField(valueKind reflect.Kind, values []string, field reflect.Value) (bool, error) {
304+
if valueKind == reflect.Ptr {
305+
if field.IsNil() {
306+
field.Set(reflect.New(field.Type().Elem()))
307+
}
308+
field = field.Elem()
295309
}
296-
}
297310

298-
func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
299311
fieldIValue := field.Addr().Interface()
300-
if unmarshaler, ok := fieldIValue.(BindUnmarshaler); ok {
301-
return true, unmarshaler.UnmarshalParam(value)
302-
}
303-
if unmarshaler, ok := fieldIValue.(encoding.TextUnmarshaler); ok {
304-
return true, unmarshaler.UnmarshalText([]byte(value))
312+
unmarshaler, ok := fieldIValue.(bindMultipleUnmarshaler)
313+
if !ok {
314+
return false, nil
305315
}
306-
307-
return false, nil
316+
return true, unmarshaler.UnmarshalParams(values)
308317
}
309318

310-
func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) {
311-
if field.IsNil() {
312-
// Initialize the pointer to a nil value
313-
field.Set(reflect.New(field.Type().Elem()))
319+
func unmarshalInputToField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
320+
if valueKind == reflect.Ptr {
321+
if field.IsNil() {
322+
field.Set(reflect.New(field.Type().Elem()))
323+
}
324+
field = field.Elem()
314325
}
315-
return unmarshalFieldNonPtr(value, field.Elem())
326+
327+
fieldIValue := field.Addr().Interface()
328+
switch unmarshaler := fieldIValue.(type) {
329+
case BindUnmarshaler:
330+
return true, unmarshaler.UnmarshalParam(val)
331+
case encoding.TextUnmarshaler:
332+
return true, unmarshaler.UnmarshalText([]byte(val))
333+
}
334+
335+
return false, nil
316336
}
317337

318338
func setIntField(value string, bitSize int, field reflect.Value) error {

0 commit comments

Comments
 (0)