In my humble opinion, Golang is pretty verbose in a bad way when it comes to JSON. Rust and the crate serde_json are also strongly typed and it's a lot better.
Yeah, having done this, it's extremely verbose if you have all your error handling in there due to the verbosity of dealing with JSON and explicit return values instead of exceptions. By far my greatest annoyance is that []interface{} cannot be directly cast to []concreteType. Having to make a sized slice and type assert each value is annoying. Require validation of the values for even more "if err != nil" fun.
Many Go advocates seem to consider the verbosity a feature, because it's explicit and forbids any clever-but-confusing tricks.
> XYZ’s protocol is not just based on JSON, but it’s based on a particular technique known as polymorphic JSON. In this, a single field could have a different data type in different circumstances. For example, the resources field can be an array when requesting a single access token, or it can be an object when requesting multiple named access tokens. The difference in type indicates a difference in processing from the server. Within the resources array, each element can be either an object, representing a rich resource request description, or a string, representing a resource handle (scope).
The only time I've ever encountered an API that used it extensively, it was done by a company that does all their implementation in Java.
My best guess at what happened, based on the shape of the API, is that they implemented it by taking their pre-existing domain model, which had a fairly deep subclassing hierarchy, liberally sprinkled some annotations from com.fasterxml.jackson.annotation, and dumped the result straight onto the wire.
You could absolutely do an object-oriented codebase where two different subclasses have fields with the same name and different types, and, depending on how you structure your code, it might not be too painful. And it's fairly easy to imagine someone serializing a structure like that to JSON without ever meditating on the fact that JSON won't retain the all the type information.
Ironically, the end result was an API that is nigh-impossible to consume from Java. I ended up writing a façade in Python.
I've also seen little bits of this happen in the internal APIs at my current company. Also a Java shop, also a result of trying to directly connect an internal object model to the API. I've never seen it done in an API implemented in a dynamic or functional language.
I generally try to design APIs from a consumer perspective, and then usually I end up with something RESTful. Let the server do whatever it has to do, you know?
You have to implement UnmarshalJSON. Between each attempt to deserialize into a possible struct, be careful to return on errors that are not JSON serialisation errors (for example caused by reading from the underlying Reader, etc.)
It's ugly and verbose but there is no need to use empty interface.
The only time I've had to deal with it in the wild was a terrible experience. As a consumer, you couldn't make any decisions with confidence without first making a careful study of the documentation. For every. single. decision.