CoinMarketCap API with Alamofire decoding data error

76 Views Asked by At

I'm trying to get lastest list crypto datas from CoinMarketCap API with alamofire. The network request is return success but response data can't filling up. Is there any solution idea for me?

Here is my request func in ViewModel:

final class AllCurrenciesViewModel: AllCurrenciesViewModelProtocol {
    public var didSuccess: ()->() = {}
    public var didFailure: (String)->() = {_ in}
    
    private var currenciesData: CurrencyResponse?
    
    func requestAllCurrencies() {
        LastestCurrenciesRequest(start: 1, limit: 1, sort: "market_cap", currencyType: "all").request { [weak self] response in
            guard let self = self else { return }
            self.currenciesData = response?.entity
            self.didSuccess()
        } failure: { (error) in
            self.didFailure(error.message ?? "")
        }
    }
}

Here is my RequestManager:

private static func createRequest(_ request: RequestDelegate) -> DataRequest {
    print("Path: \(request.path)")
    print("RequestMethod: \(request.method.rawValue)" + " || " + "RequestParameters:", (request.parameters ?? "nil"))
    
    let request  = AF.request(apiUrl+request.path, method: request.method, parameters: request.parameters, encoding: request.enconding!, headers: HTTPHeaders(generateHeader() ?? ["":""]))
    request.validate()
    
    request.responseData { (response) in
        if let value = response.data {
            debugPrint("REQUEST: \(response.request)")
            if let json = String(data: value, encoding: .utf8) {
                let cleanJson = json.replacingOccurrences(of: "\\/", with: "/")
                print("Data:" + cleanJson)
            }
        }
    }

    return request
}

static func request<T: Codable>(_ request: RequestDelegate, success: @escaping ObjectClosure<T>, failure: @escaping ErrorClosure) {
    let request = createRequest(request)
    
    request.responseData { (response) in
        switch response.result {
        case .success:
            debugPrint("REQUEST: \(response.request)")
            if let data = response.data, let model = ResponseObjectModel<T>.decode(data) {
                success(model)
            } else if let data = response.data {
                if let jsonResponse = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
                    let isSuccess = jsonResponse["error_message"]
                    if (isSuccess ?? false) as! Bool{
                        success(nil)
                    } else {
                        handleFailure(response: response, failure: failure)
                    }
                }
            } else {
                handleFailure(response: response, failure: failure)
            }
        case .failure:
            handleFailure(response: response, failure: failure)
        }
    }
}

Here is my ResponseObjectModel:

class ResponseObjectModel<T: Codable>: BaseResponseModel {
    var entity: T?
    
    enum CodingKeys: String, CodingKey {
        case entity = "data"
    }
    
    required init(from decoder: Decoder) throws {
        do {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            entity = try container.decode(T.self, forKey: .entity)
            try super.init(from: decoder)
        } catch {
            print("error decoding entity: \(error)")
            throw error
        }
    }
}

I've got error this point decoding entity:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

And here is json model:

{
  "status": {
    "timestamp": "2023-11-30T16:18:17.277Z",
    "error_code": 0,
    "error_message": null,
    "elapsed": 35,
    "credit_count": 1,
    "notice": null,
    "total_count": 8848
  },
  "data": [
    {
      "id": 1,
      "name": "Bitcoin",
      "symbol": "BTC",
      "slug": "bitcoin",
      "num_market_pairs": 10577,
      "date_added": "2010-07-13T00:00:00.000Z",
      "tags": [
        "mineable",
        "pow",
        "sha-256",
        "store-of-value",
        "state-channel",
        "coinbase-ventures-portfolio",
      ],
      "max_supply": 21000000,
      "circulating_supply": 19557106,
      "total_supply": 19557106,
      "infinite_supply": false,
      "platform": null,
      "cmc_rank": 1,
      "self_reported_circulating_supply": null,
      "self_reported_market_cap": null,
      "tvl_ratio": null,
      "last_updated": "2023-11-30T16:17:00.000Z",
      "quote": {
        "USD": {
          "price": 37615.098096097085,
          "volume_24h": 19255617190.253216,
          "volume_change_24h": -26.5108,
          "percent_change_1h": -0.22835089,
          "percent_change_24h": -0.23443231,
          "percent_change_7d": 1.34443149,
          "percent_change_30d": 9.61958301,
          "percent_change_60d": 38.54515832,
          "percent_change_90d": 45.95563552,
          "market_cap": 735642460665.7689,
          "market_cap_dominance": 51.8664,
          "fully_diluted_market_cap": 789917060018.04,
          "tvl": null,
          "last_updated": "2023-11-30T16:17:00.000Z"
        }
      }
    }
  ]
}

Here is my BaseResponseModel:

class BaseResponseModel: Codable {
    var status: CurrencyStatus?
    var data: [CurrencyResponse?]
    
    enum CodingKeys: String, CodingKey {
        case status
        case data
    }
}

struct CurrencyStatus: Codable {
    var timeStamp: String?
    var errorCode: Int?
    var errorMessage: String?
    var elapsed: Int?
    var creditCount: Int?
    var notice: String?
    
    enum CodingKeys: String, CodingKey {
        case timeStamp = "timestamp"
        case errorCode = "error_code"
        case errorMessage = "error_message"
        case elapsed
        case creditCount = "credit_count"
        case notice
    }
}

struct CurrencyResponse: Codable {
    var id: Int?
    var name: String?
    var symbol: String?
    var slug: String?
    var cmcRank: Int?
    var numMarketPairs: Int?
    var circulatingSupply: Int?
    var totalSupply: Int?
    var maxSupply: Int?
    var queto: Quote?
    var lastUpdated: String?
    var dateAdded: String?
    var tags: [String?]
}
0

There are 0 best solutions below