Search code examples
jsonswiftapiparsingdecodable

What are structs should be according to API docs to parse data from response?


I need structs to decode surface wind data.

https://api.windy.com/point-forecast/docs

The body of response from API docs:

{
    ts:int[],
    units: {
        {parameter-level}: string,
        {parameter2-level}: string,
        ...
    },
    {parameter-level}: float[],
    {parameter2-level}: float[],
    ...

}

Managed to decode successfully only ts:int[] to this struct:

struct Response: Codable {
    var ts: [Int]
}

Also I need structs to decode data of surface wind.


Solution

  • You could try this approach, using dynamic keys, works in my tests:

    struct ResponseAPI: Decodable {
        var ts: [Int]
        var units: [String:String]
        var data: [String:[Float]]
    
        init(ts: [Int], units: [String:String], data: [String:[Float]]) {
           self.ts = ts
           self.units = units
           self.data = data
        }
        
        enum CodingKeys: String, CodingKey {
            case ts, units
        }
        
        struct AnyKey: CodingKey {
            var stringValue: String
            var intValue: Int?
            
            init?(stringValue: String) {  self.stringValue = stringValue  }
            init?(intValue: Int) { return nil } // never used
        }
        
        init(from decoder: Decoder) throws {
            let container1 = try decoder.container(keyedBy: CodingKeys.self)
            self.ts = try container1.decode([Int].self, forKey: .ts)
            self.units = try container1.decode([String:String].self, forKey: .units)
            self.data = [:]
            let container2 = try decoder.container(keyedBy: AnyKey.self)
            container2.allKeys.forEach { key in
                if let theFloats = try? container2.decode([Float].self, forKey: key) {
                    self.data[key.stringValue] = theFloats
                }
            }
        }
        
    }