// Unpack populates the fields of the struct pointed to by ptr
// from the HTTP request parameters in req.
func Unpack(req *http.Request, ptr interface{}) error {
if err := req.ParseForm(); err != nil {
return err
}
// Build map of fields keyed by effective name.
fields := make(map[string]reflect.Value)
v := reflect.ValueOf(ptr).Elem() // the struct variable
for i := 0; i < v.NumField(); i++ {
fieldInfo := v.Type().Field(i) // a reflect.StructField
tag := fieldInfo.Tag // a reflect.StructTag
name := tag.Get("http")
if name == "" {
name = strings.ToLower(fieldInfo.Name)
}
fields[name] = v.Field(i)
}
// Update struct field for each parameter in the request.
for name, values := range req.Form {
f := fields[name]
if !f.IsValid() {
continue // ignore unrecognized HTTP parameters
}
for _, value := range values {
if f.Kind() == reflect.Slice {
elem := reflect.New(f.Type().Elem()).Elem()
if err := populate(elem, value); err != nil {
return fmt.Errorf("%s: %v", name, err)
}
f.Set(reflect.Append(f, elem))
} else {
if err := populate(f, value); err != nil {
return fmt.Errorf("%s: %v", name, err)
}
}
}
}
return nil
}