I'm asking this about Go's encoding/json
, but I guess it also applies to any other JSON libraries that map JSON blobs to objects in whatever language.
Here's an example. If you want to a shorten a URL using the goo.gl URL shortener API, you get back either a successful response:
{
"kind": "urlshortener#url",
"id": "http://goo.gl/fbsS",
"longUrl": "http://www.google.com/"
}
Or an error response:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Required",
"locationType": "parameter",
"location": "resource.longUrl"
}
],
"code": 400,
"message": "Required"
}
}
Is there an idiomatic way of dealing with this -- a response that could adhere to two completely different schemas?
Normally I deal with JSON using maps/lists; I know that's possible in Go. I could unmarshal to a map[string]interface{}
and then check if the map has "error"
as a key. But then I'd have to decode again into a proper struct
, I think. (Am I wrong?)
I'm doing something like this. I have one type for each kind of response:
type successResponse struct {
Kind string
Id string
LongUrl string
}
type errorResponse struct {
Error struct {
Errors []struct {
Domain string
Reason string
Message string
LocationType string
Location string
}
Code int
Message string
}
}
And decoding looks like this:
s := new(successResponse)
err := json.Unmarshal(blob, s)
if err == nil {
// handle success
} else {
e := new(errorResponse)
err = json.Unmarshal(blob, e)
if err == nil {
// handle error response
} else {
// handle actual error
}
}
But that seems kind of ugly. How should I approach this?