I was fetching data from an API returning an array but needed to replace it by an API that has "sub levels":
RAW:
ETH:
USD:
TYPE: "5"
MARKET: "CCCAGG"
FROMSYMBOL: "ETH"
TOSYMBOL: "USD"
PRICE: 680.89
CHANGEPCT24HOUR : -9.313816893529749
Here is my struct:
struct Ethereum: Codable {
let percentChange24h: String
let priceUSD: String
private enum CodingKeys: String, CodingKey {
case priceUSD = "PRICE", percentChange24h = "CHANGEPCT24HOUR"
}
}
And the implementation:
func fetchEthereumInfo(completion: @escaping (Ethereum?, Error?) -> Void) {
let url = URL(string: "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
do {
if let ethereumUSD = try JSONDecoder().decode([Ethereum].self, from: data).first {
print(ethereumUSD)
completion(ethereumUSD, nil)
}
} catch {
print(error)
}
}
task.resume()
}
The console prints typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))
I can't really figure out what to update in my code or what this form of API is
First of all the JSON does not contain any array. It's very very easy to read JSON. There are only 2 (two!) collection types, array []
and dictionary {}
. As you can see there are no square brackets at all in the JSON string.
Any (sub)dictionary {}
has to be decoded to its own type, so it's supposed to be
struct Root : Decodable {
private enum CodingKeys : String, CodingKey { case raw = "RAW" }
let raw : RAW
}
struct RAW : Decodable {
private enum CodingKeys : String, CodingKey { case eth = "ETH" }
let eth : ETH
}
struct ETH : Decodable {
private enum CodingKeys : String, CodingKey { case usd = "USD" }
let usd : USD
}
struct USD : Decodable {
private enum CodingKeys : String, CodingKey {
case type = "TYPE"
case market = "MARKET"
case price = "PRICE"
case percentChange24h = "CHANGEPCT24HOUR"
}
let type : String
let market : String
let price : Double
let percentChange24h : Double
}
To decode the JSON and and print percentChange24h
you have to write
let result = try JSONDecoder().decode(Root.self, from: data)
print("percentChange24h", result.raw.eth.usd.percentChange24h)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With