'I can't pull Json data while doing MVVM design project with swift

I am making a project in Swift with MVVM design. I want to get coin name, current price, Rank and Symbol from a Crypto site. I can't show the json data I get on the console. The model is in another folder because I did it with MVVM. How can I create a struct to get the data here? You can find screenshots of my project below. I would be glad if you help.

Below are the codes I wrote in my web service file

import Foundation

class WebService {
    

    func downloadCurrencies(url: URL, completion: @escaping ([DataInfo]?) -> ()) {
        
        URLSession.shared.dataTask(with: url) { (data, response, error) in
            
            if let error = error {
                print(error.localizedDescription)
                completion(nil)
                
            } else if let data = data {
                
                let cryptoList = try? JSONDecoder().decode([DataInfo].self, from: data)
                
                print(cryptoList)
                
                if let cryptoList = cryptoList {
                    completion(cryptoList)
                }
            }
            
        }
        .resume()
    }
}

Below are the codes I wrote in my model file

import Foundation

struct DataInfo : Decodable {
    
    var name: String
    var symbol: String
    var cmc_rank: String
    var usd: Double
    
}

Finally, here is the code I wrote to print the data in the viewController to my console. But unfortunately I can't pull the data.

override func viewDidLoad() {
    super.viewDidLoad()
   
    let url = URL(string: "https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=1&limit=10&convert=USD&CMC_PRO_API_KEY=5ac24b80-27a1-4d01-81bd-f19620533480")!
    
    WebService().downloadCurrencies(url: url) { cryptos in
        if let cryptos = cryptos {
            print(cryptos)

        }
    }
}


Solution 1:[1]

I've seen your URL and tested it ON Postman and also i've got your code and tried to put it in a shape, the code is good, but it can't MAP JSON Data against your struct because this is the json Data from Postman Postman Data

While Looking at your Struct, It Doesnt Match the format of JSON Data you're receiving,

Struct

Well, To Make your structure match the JSON String you need to create Nested String: Any Dictionary. But there's another issue with the logic, you need to decode data outside of the webservice call because it can contain errors which wont be mapped in the struct and can handle if you get other statusCode.

If you try to implement all these things manually, the code will become complex and hard to understand. I would rather recommend you to use Alamofire with SwiftyJSON and it can make your work a lot shorter and easier and understandable.

Sorry for the bad english.

Solution 2:[2]

Your api-key is not valid for me. Your data must be inside of object or invalid keys and you are surely missing it thats why it is not parsing correctly.

My suggestion is to put your json response in this website

"https://app.quicktype.io/"

and replace your struct with new one, you will be good to go hopefully.

Solution 3:[3]

Your models are incorrect, try these

struct Response: Codable {
    let status: Status
    let data: [CurrencyData]
}

struct Status: Codable {
    let creditCount: Int
    let elapsed: Int
    let timestamp: String
    let totalCount: Int
    let errorCode: Int?
    let errorMessage: String?
    let notice: String?

    enum CodingKeys: String, CodingKey {
        case notice
        case timestamp
        case elapsed
        case creditCount = "credit_count"
        case errorCode = "error_code"
        case errorMessage = "error_message"
        case totalCount = "total_count"
    }
}

enum Currency: String, Codable, Hashable {
    case usd = "USD"
}

struct CurrencyData: Codable {
    let circulatingSupply: Double?
    let cmcRank: Int
    let dateAdded: String?
    let id: Int
    let lastUpdated: String?
    let maxSupply: Int?
    let name: String
    let numMarketPairs: Int
    let platform: Platform?
    let quote: [String: Price]
    let selfReportedCirculatingSupply: String?
    let selfReportedMarketCap: String?
    let slug: String
    let symbol: String
    let tags: [String]?
    let totalSupply: Double
    
    func price(for currency: Currency) -> Double? {
        return quote[currency.rawValue]?.price
    }

    enum CodingKeys: String, CodingKey {
        case id
        case name
        case platform
        case quote
        case slug
        case symbol
        case tags
        case circulatingSupply = "circulating_supply"
        case cmcRank = "cmc_rank"
        case dateAdded = "date_added"
        case lastUpdated = "last_updated"
        case maxSupply = "max_supply"
        case selfReportedCirculatingSupply = "self_reported_circulating_supply"
        case selfReportedMarketCap = "self_reported_market_cap"
        case totalSupply = "total_supply"
        case numMarketPairs = "num_market_pairs"
    }
}

struct Price: Codable {
    let fullyDilutedMarketCap: Double?
    let lastUpdated: String?
    let marketCap: Double?
    let marketCapDominance: Double?
    let percentChange1h: Double?
    let percentChange24h: Double?
    let percentChange30d: Double?
    let percentChange60d: Double?
    let percentChange7d: Double?
    let percentChange90d: Double?
    let price: Double?
    let volume24h: Double?
    let volumeChange24h: Double?

    enum CodingKeys: String, CodingKey {
        case price
        case fullyDilutedMarketCap = "fully_diluted_market_cap"
        case lastUpdated = "last_updated"
        case marketCap = "market_cap"
        case marketCapDominance = "market_cap_dominance"
        case percentChange1h = "percent_change_1h"
        case percentChange24h = "percent_change_24h"
        case percentChange30d = "percent_change_30d"
        case percentChange60d = "percent_change_60d"
        case percentChange7d = "percent_change_7d"
        case percentChange90d = "percent_change_90d"
        case volume24h = "volume_24h"
        case volumeChange24h = "volume_change_24h"
    }
}

struct Platform: Codable {
    let id: Int
    let name: String
    let symbol: String
    let slug: String
    let tokenAddress: String?
    
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case symbol
        case slug
        case tokenAddress = "token_address"
    }
}

Also it's not safe to expose your personal data to the internet (API_KEY, etc.)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Hashim Khan
Solution 2 DevIOS
Solution 3 narek.sv