Reputation: 1720
All questions I have found so far on the searches I've done is about decoding nested JSON to some struct with nested properties. I want to do the opposite: decode flat JSON to a struct with nested properties.
Here's example JSON:
{
"id":"ABC123",
"cell":"test",
"qty":24
}
which I'd like to decode to this struct:
struct InventoryItem {
let id: String
let mfgInfo: MfgInfo
}
extension InventoryItem {
struct MfgInfo {
let cell: String
let qty: Int
}
}
I have tried adding CodingKeys for each struct:
struct InventoryItem: Decodable {
let id: String
let mfgInfo: MfgInfo
enum CodingKeys: String, CodingKey {
case id, mfgInfo
}
}
struct MfgInfo: Decodable {
let cell: String
let qty: Int
enum CodingKeys: String, CodingKey {
case cell, qty
}
}
But this doesn't work. I get this error:
No value associated with key CodingKeys(stringValue: \"mfgInfo\", intValue: nil) (\"mfgInfo\"), converted to mfg_info.
How can I make this work without a custom initializer? Or do I need to write a custom init(with: Decoder)
initializer?
Upvotes: 0
Views: 252
Reputation: 1720
I wasn't able to do this without implementing the init(from: Decoder)
initializer, but it was easier than I thought. For nested structs that just have primitive types, you can just use the automatically synthesized init(from: Decoder)
method.
Final struct setup:
struct InventoryItem: Decodable {
let id: String
let mfgInfo: MfgInfo
enum CodingKeys: String, CodingKey {
case id
}
struct MfgInfo: Decodable {
let cell: String
let qty: Int
enum CodingKeys: String, CodingKey {
case cell, qty
}
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
mfgInfo = try MfgInfo(from: decoder)
}
}
Upvotes: 1
Reputation: 17844
This is only possible with a custom init(with: Decoder)
implementation, or by having e.g. a FlatInventoryItem
type that conforms to Decodable
and then providing conversion methods between that and your desired InventoryItem
type.
Upvotes: 0