all.
I'm trying to create a struct to hold the contents of an API call that has a certain structure, but not sure how to write it.
Here's one result from the API where I'm having issues coding the receiving struct for:
"10E": {
"baseSetSize": 264,
"block": "Guilds of Ravnica",
"boosterV3": [
[
"rare",
"mythic rare"
],
"uncommon",
"uncommon",
"uncommon",
"common",
"common",
"common",
"common",
"common",
"common",
"common",
"common",
"common",
"common",
"land",
"marketing"
],
"cards": [ ... ]
}
The API lists the 'boosterV3' key as having the format array(array, string)
. However, some the returned data contains an array of 16 strings, and at least one has an array of strings as it's first element.
I've tried using the following struct:
struct MtGSet : Codable {
let name: String
let baseSetSize: Int
let block: String
let boosterV3: [String]
let cards: [MtGCard]
}
But running against the API with this generates this error:
[CodingKeys(stringValue: "boosterV3", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)],
debugDescription: "Expected to decode String but found an array instead.", underlyingError: nil))
Is it possible to write a data structure in Swift that would accept either 16 String values or 15 String values and 1 array of String for the boosterV3
key?
Thanks.
Try like the below. I am not testing this I just created by converting JSON to Swift. you can also do it by yourself, here it is https://app.quicktype.io/.
struct MtGSet : Codable {
let name: String
let baseSetSize: Int
let block: String
let boosterV3: [BoosterV3] // user [] of BoosterV3 instead of string
let cards: [MtGCard]
}
enum BoosterV3: Codable {
case string(String)
case stringArray([String])
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode([String].self) {
self = .stringArray(x)
return
}
if let x = try? container.decode(String.self) {
self = .string(x)
return
}
throw DecodingError.typeMismatch(BoosterV3.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for BoosterV3"))
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .string(let x):
try container.encode(x)
case .stringArray(let x):
try container.encode(x)
}
}
}