rubberchicken
rubberchicken

Reputation: 1322

How to decode a nested JSON struct with dynamic variable from API call

When calling to this specific API, one of the variables changes based on the results.

Example:

{
    "map": {
        "1945206": {
            "installBaseNUMB": 0,
            "serialNumber": "KB1",
            ...
        }
    }
}

1945206 will change to another number and I don't know how to properly decode this.

My Codable struct is as follows:

struct Map: Codable {
    let the1945206: The1945206?

    enum CodingKeys: String, CodingKey {
        case the1945206 = "1945206"
    }
}

struct The1945206: Codable {
    let installBaseNUMB: Int?
    let serialNumber, woStatus: String?
    let workOrderNumber: Int?
    let woNotes: [String]?
    let woParts: [WoPart]?
}

If 1945206 changes to another value, it breaks and won't show any results. How do I use a dynamic variable in decoding the data?

Upvotes: 1

Views: 306

Answers (3)

Meseery
Meseery

Reputation: 1855

Try this:

struct Install: Decodable {
    let installBaseNUMB: Int, serialNumber: String
}

let installData = try? JSONDecoder().decode([String:[String:Install]].self, from: jsonData2!)
let install = installData?.values.first?.values.first

Upvotes: 0

Shehata Gamal
Shehata Gamal

Reputation: 100541

You can try

struct Root : Codable {
   let map: [String:The1945206]
}

let res = try? JSONDecoder().decode(Root.self,from:data)
print(res?.map.values)

{
    "map": {
        "1945204": {
            "installBaseNUMB": 0,
            "serialNumber": "KB1",
            ...
        },
        "1945205": {
            "installBaseNUMB": 0,
            "serialNumber": "KB1",
            ...
        },
        "1945206": {
            "installBaseNUMB": 0,
            "serialNumber": "KB1",
            ...
        }
    }
}

Upvotes: 1

Maciej Gad
Maciej Gad

Reputation: 1741

I will suggest setting different names than The1945206 as it is less readable. I will use MapElement instead. If you know that map will have only one element, and you don't want to check what key is associated with this value, you can use computed property var value:MapElement? to get it. It returns an optional, because let map:[String:MapElement] dictionary can be empty.

let json = """
{
    "map": {
        "1945206": {
            "installBaseNUMB": 0,
            "serialNumber": "KB1"
        }
    }
}
""".data(using: .utf8)!

struct Container: Codable {
    let map:[String:MapElement]

    var value:MapElement? {
        return map.values.first
    }
}

struct MapElement: Codable {
    let installBaseNUMB: Int
    let serialNumber: String
}

let res = try? JSONDecoder().decode(Container.self,from:json)
print(res?.value as Any)

Update:

If you want to use multiple MapElement you can change var value:MapElement to var values:[MapElement] like that:

struct Container: Codable {
    let map:[String:MapElement]

    var values:[MapElement] {
        return map.values
    }
}

But keep in mind that you are storing data as a dictionary so the order of elements is not guaranteed.

Upvotes: 0

Related Questions