Go: JSON and broken APIs
If you’ve ever used Go to decode the JSON response returned by a PHP API, you’ll probably have ran into this error:
json: cannot unmarshal array into Go struct field Obj.field of type map[string]string
The problem here being that PHP, rather than returning the empty object you
expected ({}), returns an empty array ([]). Not completely unexpected: in
PHP there’s no difference between maps/objects and arrays.
Sometimes you can fix the server:
return (object)$mything;This ensures that an empty $mything becomes {}.
But that’s not always possible, you might have to work around it on the client. With Go, it’s not all that hard.
First, define a custom type for your object:
type MyObj struct {
...
Field map[string]string `json:"field"`
...
}Becomes:
type MyField map[string]string
type MyObj struct {
...
Field MyField `json:"field"`
...
}Then implement the Unmarshaler interface:
func (t *MyField) UnmarshalJSON(in []byte) error {
if bytes.Equal(in, []byte("[]")) {
return nil
}
m := (*map[string]string)(t)
return json.Unmarshal(in, m)
}And that’s it! JSON deserialization will now gracefully ignore empty arrays returned by PHP.
Some things of note:
- The method is defined on a pointer receiver (
*MyField). This is needed to correctly update the underlying map. - I’m casting the
tobject tomap[string]string. This avoids infinite recursion when we later calljson.Unmarshal().
Related
- Go: debugging multiple response.WriteHeader calls (January 26, 2018)
- sql-migrate slides (February 9, 2016)
- Zend Framework 1.8 Web Application Development (December 2, 2009)
- Zend_Service_Mollom 1.2.0 (December 21, 2008)
- Zend_Service_Mollom 1.0.0 & 1.1.0 (December 7, 2008)