When I am converting JSON from coinapi.com (https://rest-sandbox.coinapi.io/v1/assets/?apikey=72869C8A-D49B-4DC5-9A3B-17D9804AEE97) I am getting a problem "The data couldn’t be read because it isn’t in the correct format".
As result at the end after converting I have:
struct CryptListStruct: Codable {
let assetID, name: String
let typeIsCrypto: Int
let dataQuoteStart, dataQuoteEnd, dataOrderbookStart, dataOrderbookEnd: String
let dataTradeStart, dataTradeEnd: String
let dataSymbolsCount: Int
let volume1HrsUsd, volume1DayUsd: Double
let volume1MthUsd: Int
let priceUsd: Double?
let idIcon, dataStart, dataEnd: String
enum CodingKeys: String, CodingKey {
case assetID = "asset_id"
case name
case typeIsCrypto = "type_is_crypto"
case dataQuoteStart = "data_quote_start"
case dataQuoteEnd = "data_quote_end"
case dataOrderbookStart = "data_orderbook_start"
case dataOrderbookEnd = "data_orderbook_end"
case dataTradeStart = "data_trade_start"
case dataTradeEnd = "data_trade_end"
case dataSymbolsCount = "data_symbols_count"
case volume1HrsUsd = "volume_1hrs_usd"
case volume1DayUsd = "volume_1day_usd"
case volume1MthUsd = "volume_1mth_usd"
case priceUsd = "price_usd"
case idIcon = "id_icon"
case dataStart = "data_start"
case dataEnd = "data_end"
}
}
I think it is because of a lot of data there and they are not the same. How can I get the correct model?
That's how my function looks like:
func getCryptList(_ completion: @escaping (CryptListStruct) -> Void, _ error: @escaping (String) -> Void){
let header: [String: String] = [:]
self.get(url: "https://rest.coinapi.io/v1/assets/?apikey=367FB27A-371B-4DBD-AB81-E98AAFE857B2", header: header, completion: {
(data) in
do {
guard let data = data else {return}
let crpytList = try JSONDecoder().decode(CryptListStruct.self, from: data)
DispatchQueue.main.async {
completion(crpytList)
}
} catch let err {
error(err.localizedDescription)
}
}, error: error)
}
``
First of all
print(error.localizedDescription)
.in a JSONDecoder
catch block. You get a generic but quite meaningless error message.
Always print the entire error, DecodingError
s are very descriptive
print(error)
Your code contains three major errors, one of them (error #3) occurs multiple times
Error #1
typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
indicates that the root object is an array, the JSON starts clearly with [
Solution: Decode [CryptListStruct].self
Error #2
dataCorrupted(Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "volume_1mth_usd", intValue: nil)], debugDescription: "Parsed JSON number <3699822674922524.74> does not fit in Int.", underlyingError: nil))
indicates that the received value 3699822674922524.74
is actually a Double
.
Solution: Declare
let volume1MthUsd: Double
Error #3
keyNotFound(CodingKeys(stringValue: "id_icon", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 4", intValue: 4)], debugDescription: "No value associated with key CodingKeys(stringValue: "id_icon", intValue: nil) ("id_icon").", underlyingError: nil))
indicates that the key id_icon
is missing (at least) in the 5th item of the array.
Solution: Declare the type as optional
let idIcon : String?
The same error occurs for dataTradeStart
, dataTradeEnd
, dataQuoteStart
, dataQuoteEnd
, dataOrderbookStart
, dataOrderbookEnd
, dataStart
, dataEnd
let dataQuoteStart, dataQuoteEnd, dataOrderbookStart, dataOrderbookEnd: String?
let dataTradeStart, dataTradeEnd : String?
let dataStart, dataEnd: String?
Side note:
You can delete the entire CodingKeys enum if you replace assetID
with assetId
and add the convertFromSnakeCase
key decoding strategy
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let crpytList = try decoder.decode([CryptListStruct].self, from: data)