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
t
object 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)