Home > database >  Unable to process API data and decode into json swift in Xcode
Unable to process API data and decode into json swift in Xcode

Time:10-27

Summary

I am attempting to get data from an API and decode it into a json

I have 2 questions about the below code

  1. is the output from apiOutput variable suitable to decode into a json format if not how do I get the correct output? I am thinking it might be changing the options in JSONSerialization.jsonObject

  2. how do I feed my apiOutput variable to my PriceApiModel.swift which I am hoping is capable of decoding apiOutput into the correct json format. Even if PriceApiModel.swift is able to do this I am unsure how to feed apiOutput into it

This image is of the data the API is returning the API data

My attempt at getting to the API data after its been called please see full code below

// from AppDelegate.swift full file included below
let apiOutput = try JSONSerialization.jsonObject(with: data!, options: [])
print(apiOutput) // please see output below

Output from printing apiOutput

{
    askPrice = "0.07530300";
    askQty = "28.15780000";
    bidPrice = "0.07530200";
    bidQty = "20.99700000";
    closeTime = 1666814307216;
    count = 389744;
    firstId = 383543634;
    highPrice = "0.07593900";
    lastId = 383933377;
    lastPrice = "0.07530300";
    lastQty = "11.85740000";
    lowPrice = "0.07230700";
    openPrice = "0.07365100";
    openTime = 1666727907216;
    prevClosePrice = "0.07365200";
    priceChange = "0.00165200";
    priceChangePercent = "2.243";
    quoteVolume = "13084.96427533";
    symbol = ETHBTC;
    volume = "176432.41160000";
    weightedAvgPrice = "0.07416418";
}

I have made PriceApiModel.swift to try and decode the above output. However do not believe I have the right options in JSONSerialization because the output looks more like variables than a json file.

// PriceApiModel.swift
import Foundation
import SwiftUI
import CoreLocation

struct PriceApiModel: Hashable, Codable {
    var askPrice: String
    var askQty: String
    var bidPrice: String
    var bidQty: String
    var closeTime: Int
    var count: Int
    var firstId: Int
    var highPrice: String
    var lastId: Int
    var lastPrice: String
    var lastQty: String
    var lowPrice: String
    var openPrice: String
    var openTime: Int
    var prevClosePrice: String
    var priceChange: String
    var priceChangePercent: String
    var quoteVolume: String
    var symbol: String
    var volume: String
    var weightedAvgPrice: String

}

Full code of AppDelegate.swift

import UIKit
    
class ViewController: UIViewController {
    
    let headers = [
        "X-RapidAPI-Key": "cannot provide this please see sample outpout",
        "X-RapidAPI-Host": "binance43.p.rapidapi.com"
    ]

    let request = NSMutableURLRequest(url: NSURL(string: "https://binance43.p.rapidapi.com/ticker/24hr?symbol=ETHBTC")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
        
    
    func getData() {
        request.httpMethod = "GET"
        request.allHTTPHeaderFields = headers
        
        let session = URLSession.shared
        let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
            if (error != nil) {
                print(error)
            } else {
                let httpResponse = response as? HTTPURLResponse
                do {
                    let apiOutput = try JSONSerialization.jsonObject(with: data!, options: [])
                        
                    
                        print(apiOutput) // this is the output I am getting
                                            
                } catch {
                    print("NOT WORKING ")
                }
            }
        })
        dataTask.resume()
    }
    
}

CodePudding user response:

If you just want to decode the received data into your model you can use a JSONDecoder.

let model = try JSONDecoder().decode(PriceApiModel.self, from: data!)

But if you want to use this model further on in your code I would recommend using some usefull types for the data you recieve. I made an example for askPrice but the others would be done in a similar way.

// used for throwing errors
enum CustomError: Error{
    case decodingError
}

struct PriceApiModel: Hashable, Codable {
    //changed the String type to Decimal
    var askPrice: Decimal
    var askQty: String
    var bidPrice: String
    var bidQty: String
    var closeTime: Int
    var count: Int
    var firstId: Int
    var highPrice: String
    var lastId: Int
    var lastPrice: String
    var lastQty: String
    var lowPrice: String
    var openPrice: String
    var openTime: Int
    var prevClosePrice: String
    var priceChange: String
    var priceChangePercent: String
    var quoteVolume: String
    var symbol: String
    var volume: String
    var weightedAvgPrice: String
    
    // every property you are interested to decode needs a CodingKey.
    // You can omit values you are not interested in
    enum CodingKeys: CodingKey{
        case askPrice
    }
    
    // here you decode your data into the struct
    init(from decoder: Decoder) throws {
        // get the container
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // decode the askPrice into a String and cast it into a Decimal
        let askPrice = Decimal(string: try container.decode(String.self, forKey: .askPrice))
        // check if casting was succesfull else throw
        guard let askPrice = askPrice else{
            throw CustomError.decodingError
        }
        // assign it
        self.askPrice = askPrice
    }
}
  • Related