Search code examples
jsonswiftparsingdynamicdynamic-keyword

Swift json dynamic key parsing for json


I have json response where only just one key name change rest is same and want to parse without duplicating same struct again.

"attributes": {
  "symbol":"EUR",
  "name":"Euro",
  "precision":2,             
}
    
"attributes":{
  "symbol":"EUR",
  "name":"Euro",
  "precision_for_fiat_price":2,  
}

How can handle this precision key dynamically in json parsing


Solution

  • You can use a custom keyDecodingStrategy.

    Essentially, you write some logic that checks whether the current coding key path matches some criteria, and if it does, map that key to the precision key.

    For example:

    struct Root : Codable {
        let attributes: Attributes
    }
    
    struct Attributes : Codable {
        let symbol: String
        let name: String
        let precision: Int
        
        enum CodingKeys: CodingKey {
            case symbol
            case name
            case precision
        }
    }
    
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .custom({
        keys in
    
        // This will decode every precision_for_fiat_price key in the json as "precision".
        // You might not want this. 
        // Make this criteria stricter if you need to. An example is shown below
        if keys.last?.stringValue == "precision_for_fiat_price" {
            return Attributes.CodingKeys.precision
        }
    
        // this will only decode those precision_for_fiat_price that have "attribute" as their parent as "precision"
    //    if stringPath.suffix(2) == ["attributes", "precision_for_fiat_price"] {
    //        return Attributes.CodingKeys.precision
    //    }
        return keys.last!
    })
    let json = """
    {
        "attributes":{
                      "symbol":"EUR",
                      "name":"Euro",
                      "precision_for_fiat_price":2
                      
         }
    }
    """.data(using: .utf8)!
    let decoded = try decoder.decode(Root.self, from: json)