Search code examples
jsonswiftcodabledecodable

Swift Codable: Decoding dynamic keys


I'm trying to practice Swift's Codable API. I send a network request and I receive one single line each time as follows where I have to deal with dynamic keys :

Response example 1:

{
  "EUR": 4695.01
}

Response example 2:

{
  "USD": 479.01
}

Response example 3:

{
  "BTC": 4735.01
}

I tried this method to parse the dynamic keys :

struct ConversionResponseModel: Decodable {
    typealias destinationCurrency = String
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
    }
}

and my fetching request :

do {
    let myResult = try JSONDecoder().decode(ConversionResponseModel.self, from: data)
                print(myResult)
            } catch {
                print(error)
            }

But I get this as a result : ConversionResponseModel(), but not the currency values. It sounds like I'm missing something. Any help please. Thank you


Solution

  • You're almost there. The JSON you're getting will return a dictionary of [String:Double]. You can then covert that using:

    struct ConversionResponseModel: Decodable {
        typealias DestinationCurrency = String
        
        let currency : DestinationCurrency
        let value : Double
        
        init(from decoder: Decoder) throws {
            let container = try decoder.singleValueContainer()
            let dict = try container.decode([String:Double].self)
            guard let key = dict.keys.first else {
                throw NSError(domain: "Decoder", code: 0, userInfo: [:])
            }
            currency = key
            value = dict[key] ?? -1
        }
    }
    

    Note: taking into account Rob Napier's comment, you could substitute Decimal for Double -- see his comment on the original question for more detail