skip to Main Content

How can I parse this JSON in Swift?
This JSON is from an API, and the API provider explained the JSON’s "data" object like this.
Screenshot of the description.
The problem is that the JSON Decoder can’t decode the JSON at all. Its error message is "type mismatch".

{
    "meta": {
        "last_updated_at": "2023-02-15T12:59:59Z"
    },
    "data": {
        "ADA": {
            "code": "ADA",
            "value": 0.001978
        },
        "AED": {
            "code": "AED",
            "value": 0.002859
        },
        "AFN": {
            "code": "AFN",
            "value": 0.0696
        },
        "ALL": {
            "code": "ALL",
            "value": 0.084096
        },
        "AMD": {
            "code": "AMD",
            "value": 0.306311
        },
        "ANG": {
            "code": "ANG",
            "value": 0.001403
        },
        "AOA": {
            "code": "AOA",
            "value": 0.392615
        },
        "ARS": {
            "code": "ARS",
            "value": 0.149368
        },
        "AUD": {
            "code": "AUD",
            "value": 0.00113
        },
        "AVAX": {
            "code": "AVAX",
            "value": 4.2e-5
        },
        "AWG": {
            "code": "AWG",
            "value": 0.001403
        },
        "AZN": {
            "code": "AZN",
            "value": 0.001323
        },
        "BAM": {
            "code": "BAM",
            "value": 0.001421
        },
        "BBD": {
            "code": "BBD",
            "value": 0.001572
        },
        "BDT": {
            "code": "BDT",
            "value": 0.082699
        },
        "BGN": {
            "code": "BGN",
            "value": 0.00142
        },
        "BHD": {
            "code": "BHD",
            "value": 0.000293
        },
        "BIF": {
            "code": "BIF",
            "value": 1.616223
        },
        "BMD": {
            "code": "BMD",
            "value": 0.000778
        },
        "BNB": {
            "code": "BNB",
            "value": 3.0e-6
        },
        "BND": {
            "code": "BND",
            "value": 0.001039
        },
        "BOB": {
            "code": "BOB",
            "value": 0.005378
        },
        "BRL": {
            "code": "BRL",
            "value": 0.004062
        },
        "BSD": {
            "code": "BSD",
            "value": 0.000778
        },
        "BTC": {
            "code": "BTC",
            "value": 0
        },
        "BTN": {
            "code": "BTN",
            "value": 0.064445
        },
        "BWP": {
            "code": "BWP",
            "value": 0.010201
        },
        "BYN": {
            "code": "BYN",
            "value": 0.001965
        },
        "BYR": {
            "code": "BYR",
            "value": 15.257164
        },
        "BZD": {
            "code": "BZD",
            "value": 0.001569
        },
        "CAD": {
            "code": "CAD",
            "value": 0.001044
        },
        "CDF": {
            "code": "CDF",
            "value": 1.591884
        },
        "CHF": {
            "code": "CHF",
            "value": 0.000718
        },
        "CLF": {
            "code": "CLF",
            "value": 2.2e-5
        },
        "CLP": {
            "code": "CLP",
            "value": 0.614919
        },
        "CNY": {
            "code": "CNY",
            "value": 0.005326
        },
        "COP": {
            "code": "COP",
            "value": 3.698284
        },
        "CRC": {
            "code": "CRC",
            "value": 0.442391
        },
        "CUC": {
            "code": "CUC",
            "value": 0.000782
        },
        "CUP": {
            "code": "CUP",
            "value": 0.01868
        },
        "CVE": {
            "code": "CVE",
            "value": 0.080125
        },
        "CZK": {
            "code": "CZK",
            "value": 0.017217
        },
        "DJF": {
            "code": "DJF",
            "value": 0.138581
        },
        "DKK": {
            "code": "DKK",
            "value": 0.005422
        },
        "DOP": {
            "code": "DOP",
            "value": 0.043735
        },
        "DOT": {
            "code": "DOT",
            "value": 0.000123
        },
        "DZD": {
            "code": "DZD",
            "value": 0.106398
        },
        "EGP": {
            "code": "EGP",
            "value": 0.023798
        },
        "ERN": {
            "code": "ERN",
            "value": 0.011676
        },
        "ETB": {
            "code": "ETB",
            "value": 0.041827
        },
        "ETH": {
            "code": "ETH",
            "value": 0
        },
        "EUR": {
            "code": "EUR",
            "value": 0.000728
        },
        "FJD": {
            "code": "FJD",
            "value": 0.001706
        },
        "FKP": {
            "code": "FKP",
            "value": 0.000647
        },
        "GBP": {
            "code": "GBP",
            "value": 0.000646
        },
        "GEL": {
            "code": "GEL",
            "value": 0.002067
        },
        "GGP": {
            "code": "GGP",
            "value": 0.000647
        },
        "GHS": {
            "code": "GHS",
            "value": 0.009632
        },
        "GIP": {
            "code": "GIP",
            "value": 0.000647
        },
        "GMD": {
            "code": "GMD",
            "value": 0.047601
        },
        "GNF": {
            "code": "GNF",
            "value": 6.70225
        },
        "GTQ": {
            "code": "GTQ",
            "value": 0.006094
        },
        "GYD": {
            "code": "GYD",
            "value": 0.164233
        },
        "HKD": {
            "code": "HKD",
            "value": 0.00611
        },
        "HNL": {
            "code": "HNL",
            "value": 0.019186
        },
        "HTG": {
            "code": "HTG",
            "value": 0.116942
        },
        "HUF": {
            "code": "HUF",
            "value": 0.276597
        },
        "IDR": {
            "code": "IDR",
            "value": 11.864333
        },
        "ILS": {
            "code": "ILS",
            "value": 0.002746
        },
        "IMP": {
            "code": "IMP",
            "value": 0.000647
        },
        "INR": {
            "code": "INR",
            "value": 0.064507
        },
        "IQD": {
            "code": "IQD",
            "value": 1.135978
        },
        "IRR": {
            "code": "IRR",
            "value": 32.888583
        },
        "ISK": {
            "code": "ISK",
            "value": 0.111985
        },
        "JEP": {
            "code": "JEP",
            "value": 0.000647
        },
        "JMD": {
            "code": "JMD",
            "value": 0.120157
        },
        "JOD": {
            "code": "JOD",
            "value": 0.000553
        },
        "JPY": {
            "code": "JPY",
            "value": 0.10407
        },
        "KES": {
            "code": "KES",
            "value": 0.097763
        },
        "KGS": {
            "code": "KGS",
            "value": 0.0677
        },
        "KHR": {
            "code": "KHR",
            "value": 3.180334
        },
        "KMF": {
            "code": "KMF",
            "value": 0.357201
        },
        "KPW": {
            "code": "KPW",
            "value": 0.70051
        },
        "KRW": {
            "code": "KRW",
            "value": 1
        },
        "KWD": {
            "code": "KWD",
            "value": 0.000238
        },
        "KYD": {
            "code": "KYD",
            "value": 0.000649
        },
        "KZT": {
            "code": "KZT",
            "value": 0.347961
        },
        "LAK": {
            "code": "LAK",
            "value": 13.112856
        },
        "LBP": {
            "code": "LBP",
            "value": 11.682782
        },
        "LKR": {
            "code": "LKR",
            "value": 0.284092
        },
        "LRD": {
            "code": "LRD",
            "value": 0.122369
        },
        "LSL": {
            "code": "LSL",
            "value": 0.013942
        },
        "LTC": {
            "code": "LTC",
            "value": 8.0e-6
        },
        "LTL": {
            "code": "LTL",
            "value": 0.002298
        },
        "LVL": {
            "code": "LVL",
            "value": 0.000471
        },
        "LYD": {
            "code": "LYD",
            "value": 0.00373
        },
        "MAD": {
            "code": "MAD",
            "value": 0.008016
        },
        "MATIC": {
            "code": "MATIC",
            "value": 0.000611
        },
        "MDL": {
            "code": "MDL",
            "value": 0.014574
        },
        "MGA": {
            "code": "MGA",
            "value": 3.340641
        },
        "MKD": {
            "code": "MKD",
            "value": 0.044773
        },
        "MMK": {
            "code": "MMK",
            "value": 1.634501
        },
        "MNT": {
            "code": "MNT",
            "value": 2.741876
        },
        "MOP": {
            "code": "MOP",
            "value": 0.006292
        },
        "MRO": {
            "code": "MRO",
            "value": 0.277898
        },
        "MUR": {
            "code": "MUR",
            "value": 0.035605
        },
        "MVR": {
            "code": "MVR",
            "value": 0.011949
        },
        "MWK": {
            "code": "MWK",
            "value": 0.798893
        },
        "MXN": {
            "code": "MXN",
            "value": 0.014527
        },
        "MYR": {
            "code": "MYR",
            "value": 0.003419
        },
        "MZN": {
            "code": "MZN",
            "value": 0.049119
        },
        "NAD": {
            "code": "NAD",
            "value": 0.013942
        },
        "NGN": {
            "code": "NGN",
            "value": 0.358513
        },
        "NIO": {
            "code": "NIO",
            "value": 0.028441
        },
        "NOK": {
            "code": "NOK",
            "value": 0.007938
        },
        "NPR": {
            "code": "NPR",
            "value": 0.103111
        },
        "NZD": {
            "code": "NZD",
            "value": 0.001241
        },
        "OMR": {
            "code": "OMR",
            "value": 0.0003
        },
        "PAB": {
            "code": "PAB",
            "value": 0.000778
        },
        "PEN": {
            "code": "PEN",
            "value": 0.002993
        },
        "PGK": {
            "code": "PGK",
            "value": 0.002743
        },
        "PHP": {
            "code": "PHP",
            "value": 0.043029
        },
        "PKR": {
            "code": "PKR",
            "value": 0.20645
        },
        "PLN": {
            "code": "PLN",
            "value": 0.003466
        },
        "PYG": {
            "code": "PYG",
            "value": 5.665336
        },
        "QAR": {
            "code": "QAR",
            "value": 0.002834
        },
        "RON": {
            "code": "RON",
            "value": 0.003566
        },
        "RSD": {
            "code": "RSD",
            "value": 0.085355
        },
        "RUB": {
            "code": "RUB",
            "value": 0.057807
        },
        "RWF": {
            "code": "RWF",
            "value": 0.845186
        },
        "SAR": {
            "code": "SAR",
            "value": 0.00292
        },
        "SBD": {
            "code": "SBD",
            "value": 0.006392
        },
        "SCR": {
            "code": "SCR",
            "value": 0.010389
        },
        "SDG": {
            "code": "SDG",
            "value": 0.454602
        },
        "SEK": {
            "code": "SEK",
            "value": 0.008098
        },
        "SGD": {
            "code": "SGD",
            "value": 0.001039
        },
        "SHP": {
            "code": "SHP",
            "value": 0.000947
        },
        "SLL": {
            "code": "SLL",
            "value": 15.373958
        },
        "SOL": {
            "code": "SOL",
            "value": 3.5e-5
        },
        "SOS": {
            "code": "SOS",
            "value": 0.443315
        },
        "SRD": {
            "code": "SRD",
            "value": 0.02528
        },
        "STD": {
            "code": "STD",
            "value": 16.111862
        },
        "SVC": {
            "code": "SVC",
            "value": 0.00681
        },
        "SYP": {
            "code": "SYP",
            "value": 1.955824
        },
        "SZL": {
            "code": "SZL",
            "value": 0.013994
        },
        "THB": {
            "code": "THB",
            "value": 0.026762
        },
        "TJS": {
            "code": "TJS",
            "value": 0.008126
        },
        "TMT": {
            "code": "TMT",
            "value": 0.002724
        },
        "TND": {
            "code": "TND",
            "value": 0.00243
        },
        "TOP": {
            "code": "TOP",
            "value": 0.001815
        },
        "TRY": {
            "code": "TRY",
            "value": 0.014672
        },
        "TTD": {
            "code": "TTD",
            "value": 0.005282
        },
        "TWD": {
            "code": "TWD",
            "value": 0.023579
        },
        "TZS": {
            "code": "TZS",
            "value": 1.820522
        },
        "UAH": {
            "code": "UAH",
            "value": 0.028745
        },
        "UGX": {
            "code": "UGX",
            "value": 2.856504
        },
        "USD": {
            "code": "USD",
            "value": 0.000778
        },
        "UYU": {
            "code": "UYU",
            "value": 0.030382
        },
        "UZS": {
            "code": "UZS",
            "value": 8.848938
        },
        "VEF": {
            "code": "VEF",
            "value": 1883.620605
        },
        "VND": {
            "code": "VND",
            "value": 18.390362
        },
        "VUV": {
            "code": "VUV",
            "value": 0.090749
        },
        "WST": {
            "code": "WST",
            "value": 0.002115
        },
        "XAF": {
            "code": "XAF",
            "value": 0.476658
        },
        "XAG": {
            "code": "XAG",
            "value": 3.6e-5
        },
        "XAU": {
            "code": "XAU",
            "value": 0
        },
        "XCD": {
            "code": "XCD",
            "value": 0.002104
        },
        "XDR": {
            "code": "XDR",
            "value": 0.00058
        },
        "XOF": {
            "code": "XOF",
            "value": 0.476658
        },
        "XPF": {
            "code": "XPF",
            "value": 0.086911
        },
        "XRP": {
            "code": "XRP",
            "value": 0.001996
        },
        "YER": {
            "code": "YER",
            "value": 0.194841
        },
        "ZAR": {
            "code": "ZAR",
            "value": 0.014003
        },
        "ZMK": {
            "code": "ZMK",
            "value": 7.006775
        },
        "ZMW": {
            "code": "ZMW",
            "value": 0.015041
        },
        "ZWL": {
            "code": "ZWL",
            "value": 0.250653
        }
    }
}

I used the model below to decode the JSON above.

import Foundation

struct CurrencyAPIResponse_Latest: Codable {
    let meta: Meta
    let data: [String: Currency]
}

struct Currency: Codable {
    let code: String
    let value: Float
}

struct Meta: Codable {
    let lastUpdatedAt: Date
    
    enum CodingKeys: String, CodingKey {
        case lastUpdatedAt = "last_updated_at"
    }
}

Honestly, I’m not good at parsing JSON, so I couldn’t even try to fix this error. I just can’t understand why it keeps failing. Any help??

2

Answers


  1. One helpful thing to do is to paste your code, along with JSON (in """ quotes to allow multiline pasting) into playground and run it there.

    So when I do, the error I see is this:

    typeMismatch : 2 elements

    • .0 : Swift.Double
      ▿ .1 : Context
      ▿ codingPath : 2 elements

      • 0 : CodingKeys(stringValue: "meta", intValue: nil)
      • 1 : CodingKeys(stringValue: "last_updated_at", intValue: nil)
      • debugDescription : "Expected to decode Double but found a string/data instead."
      • underlyingError : nil

    which says pretty clearly where the problem is: you expect lastUpdatedAt to be a Date in

    let lastUpdatedAt: Date
    

    but it’s a string:

    "last_updated_at": "2023-02-15T12:59:59Z"
    

    So you have 3 options:

    Option 1: Set the date decoding strategy for the JSONDecoder. Since the format of your date is ISO8601, this will work:

    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .iso8601
    

    Option 2: If you cannot / don’t want to change JSONDecoder()‘s dateDecodingStrategy, you can make a custom conversion:

    struct Meta: Codable {
        
        static let formatter = ISO8601DateFormatter()
        
        let lastUpdatedAt: Date?
        
        init(from decoder: Decoder) throws {
            let containter = try decoder.container(keyedBy: CodingKeys.self)
            let dateAsString = try containter.decode(String.self, forKey: .lastUpdatedAt)
            lastUpdatedAt = Self.formatter.date(from: dateAsString)
        }
        
        enum CodingKeys: String, CodingKey {
            case lastUpdatedAt = "last_updated_at"
        }
    }
    

    Note that parsing may fail, and for that reason I changed lastUpdatedAt to optional. You can change the parsing in a different way.

    Option 3: Finally, you don’t always need a conversion to happen right away. In that case you can change the model to accept a string, and convert it to date later, when you actually need a date.

    struct Meta: Codable {
        
        let lastUpdatedAt: String?
        
        enum CodingKeys: String, CodingKey {
            case lastUpdatedAt = "last_updated_at"
        }
    }
    
    // ...
    
    extension String {
        
        static let formatter = ISO8601DateFormatter()
        
        var toISO8601Date: Date? {
            String.formatter.date(from: self)
        }
    }
    
    // Used as
    
    let date = meta.lastUpdatedAt.toISO8601Date
    
    Login or Signup to reply.
  2. Here is an example you could use.

    // MARK: - APIResponse
    struct APIResponse: Codable {
        let meta: Meta
        let data: [String:Currency]
        
        enum CodingKeys: String, CodingKey {
            case meta = "meta"
            case data = "data"
        }
        
        // Initializers
        init(data: Data) throws {
            self = try JSONDecoder().decode(APIResponse.self, from: data)
        }
        init(string: String, using encoding: String.Encoding = .utf8) throws {
            guard let data = string.data(using: encoding) else {
                throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
            }
            try self.init(data: data)
        }
        
    }
    
    // MARK: - Currency
    struct Currency: Codable {
        let code: String
        let value: Float
    
        enum CodingKeys: String, CodingKey {
            case code = "code"
            case value = "value"
        }
    }
    
    // MARK: - Meta
    struct Meta: Codable {
        let lastUpdatedAt: String
    
        enum CodingKeys: String, CodingKey {
            case lastUpdatedAt = "last_updated_at"
        }
    }
    

    To decode the string or data:

    Of course you have to replace jsonString or jsonData. Either with a JSON string, or with the JSON data from the server. 🙂

    do {
        // String Example:
        let apiResponse = try APIResponse(string: jsonString)
        
        // From Data Example:
        let apiResponse = try APIResponse(data: jsonData)
        
        // print(apiResponse.meta.lastUpdatedAt)   // "2023-02-15T12:59:59"
        // print(apiResponse.data.count)           // "176"
    } catch {
        print(error.localizedDescription)
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search