Heterogeneous JSON Arrays #9
diegolavalledev
announced in
Posts
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Originally published on diegolavalle.com.
As consumers of RESTful APIs we sometimes encounter JSON responses containing mixed arrays. In Swift arrays must have a single content type, so how can we parse a collection of heterogeneous elements? A solution involving enums with associated values may just be the key.
JSON mixed arrays
Because JSON is not strongly typed it can represent lists of objects with diverse structures, like this array mixing passports and driver's licenses:
[ { "country" : "United States", "fullName" : "Olivia Rodrigo", "passportNumber" : "ABC123" }, { "birth" : -63114076800, "firstName" : "Olivia", "lastName" : "Rodrigo", "licenseNumber" : 123456 } ]Swift mixed arrays
We can represent each identification type with its own
structwhile having each of them be automatically decodable and encodable into standard JSON format:In Swift if we wanted to mix passports and licenses in an array we would have to wrap those types with an
enum. Each case of the enumeration should have an associated value of the corresponding identification structure:Simple enough. We even get
Codablesupport out of the box synthesized by the compiler. But what kind of JSON representation would we get our of an identifications list?Encoding mixed arrays
We declare an array in Swift and encode to see what happens:
The resulting document will look exactly like this:
[ { "passport" : { "_0" : { "country" : "United States", "fullName" : "Olivia Rodrigo", "passportNumber" : "ABC123" } } }, { "driversLicense" : { "_0" : { "birth" : -63114076800, "firstName" : "Olivia", "lastName" : "Rodrigo", "licenseNumber" : 123456 } } } ]Note how by default Swift uses each enumeration case as key and then another positional key for the associated value. That is quite a departure from what we wanted to be able to parse initially.
Custom JSON format encoding
We can override the
encode(to:)method to get the format we want:Simply forwarding the task to the corresponding associated struct we get an output matching our original JSON example.
Custom JSON decoding
To decode from the same custom format we need to implement the
init(from:)initializer. We will arbitrarily try to decode asPassportfirst, thenDriversLicenseand if we can't we will throw a type mismatch error:Conclusion
This technique is useful for times when we do not control the format of the data that we need to parse but it's also useful in Swift world as it allows us to combine different unrelated types in one array. Furthermore, we ourselves could want to encode our
enums in a more compact way than the compiler's default.Beta Was this translation helpful? Give feedback.
All reactions