Breaking Change on v4.12.0 When Binding to map[string]interface{} -> the field become list
slzhffktm opened this issue · comments
Issue Description
Breaking change on v4.12.0:
The c.Bind
is now mapping query params & request body to list of string.
Example:
POST /test?query=param
request body
{"field1": "somevalue"}
The code
request := make(map[string]interface{})
if err := c.Bind(&request); err != nil {
return err
}
fmt.Printf("%#v", request)
Previous behaviour (pre v4.12.0):
Result: map[string]interface {}{"query":"param", "field1":"somevalue"}
Current behaviour (v4.12.0):
Result: map[string]interface {}{"query":[]string{"param"}, "field1":[]string{"somevalue"}}
Checklist
- Dependencies installed
- No typos
- Searched existing issues and docs
Expected behaviour
The behaviour from the code above should keep on returning non-breaking change and still return this on the newest version:
Result: map[string]interface {}{"query":"param", "field1":"somevalue"}
Actual behaviour
In v4.12.0, the result from the code above returned different result:
Result: map[string]interface {}{"query":[]string{"param"}, "field1":[]string{"somevalue"}}
Steps to reproduce
Working code to debug
package main
func main() {
}
Version/commit
v4.12.0
@slzhffktm I've submitted a pull request (#2656) that addresses this issue by maintaining backwards compatibility for map[string]interface{}
binding while supporting the new functionality.
The PR modifies the bindData
function to:
- Store single values as strings
- Store multiple values as
[]string
However, if the maintainers decide not to merge this change, here's an alternative solution you can use in your code to achieve the same result:
func ConvertToSingleValues(input map[string]interface{}) map[string]interface{} {
for key, value := range input {
if strSlice, ok := value.([]string); ok {
if len(strSlice) == 1 {
input[key] = strSlice[0]
}
}
}
return input
}
func ExampleFunction(c echo.Context) error {
request := make(map[string]interface{})
if err := c.Bind(&request); err != nil {
return err
}
request := ConvertToSingleValues(request)
return c.JSON(http.StatusOK, request)
}
You can use this helper function with new version without breaking code regardless of whether the PR is merged. It processes the map[string]interface{}
returned by c.Bind()
and converts any []string
values to single strings if they contain only one element.