I'm trying to use Swift 4's new JSON Decoding to parse JSON from a remote server. The JSON schema includes enum values, some of which I don't actually need for my purposes and I'd like to ignore. Additionally, I'd also like to be robust enough so that when the JSON schema changes, I will still be able to read as much of the data as I can.
The problem is that when I try to parse an array of anything containing enums, unless every enum value matches my enum's literals exactly, the decoder throws an exception rather than skipping over the data it can't parse.
Here's a simple example:
enum Size: String, Codable {
case large = "large"
case small = "small"
}
enum Label: String, Codable {
case kitchen = "kitchen"
case bedroom = "bedroom"
case livingRoom = "living room"
}
struct Box: Codable {
var contents: String
var size: Size
var labels: [Label]
}
When I parse data that completely conforms to my Size enum, I get the expected results:
let goodJson = """
[
{
"contents": "pillows",
"size": "large",
"labels": [
"bedroom"
]
},
{
"contents": "books",
"size": "small",
"labels": [
"bedroom",
"living room"
]
}
]
""".data(using: .utf8)!
let goodBoxes = try? JSONDecoder().decode([Box?].self, from: goodJson)
// returns [{{contents "pillows", large, [bedroom]}},{{contents "books", small, [bedroom, livingRoom]}}]
However, if there are contents that don't conform to the enum, the decoder throws an exception and I get nothing back.
let badJson = """
[
{
"contents": "pillows",
"size": "large",
"labels": [
"bedroom"
]
},
{
"contents": "books",
"size": "small",
"labels": [
"bedroom",
"living room",
"office"
]
},
{
"contents": "toys",
"size": "medium",
"labels": [
"bedroom"
]
}
]
""".data(using: .utf8)!
let badBoxes = try? JSONDecoder().decode([Box?].self, from: badJson) // returns nil
Ideally, in this case, I would like to get back the 2 items where size conforms to "small" or "large" and the second item wound have the 2 valid labels, "bedroom" and "living room".
If I implement my own init(from: decoder) for Box, I could decode labels myself and throw out any which don't conform to my enum. However, I can't figure out how to decode a [Box] type to ignore invalid boxes without implementing my own Decoder and parsing the JSON myself, which defeats the purpose of using Codable.
Any ideas?