Home > Blockchain >  Swift JSON decoding url
Swift JSON decoding url

Time:10-29

I'm starting to hook up my frontend SwiftUI project to a backend and so I'm learning how to make API calls in Swift. I began by trying to use the code in this video as a workable example. However, I'm running into an error where the JSONDecoder is failing to decode the returned data.

What is going on here? My apologies for the blunt question--I'm new to backend development.


let url = "https://api.sunrise-sunset.org/json?date=2020-01-01&lat=-74.060&lng=40.7128&form"
getData(from: url)
private func getData(from url: String) {
    let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { data, response, error in
        guard let data = data, error == nil else {
            print("Something Went Wrong...")
            return
        }
        // data is available
        var result: Response?
        do {
            result = try JSONDecoder().decode(Response.self, from: data)
        } catch {
            print("failed to convert \(error.localizedDescription)")
        }
        guard let json = result else {
            return
        }
        print(json.status)
        print(json.results.sunrise)
    })
    task.resume()
}

struct Response: Codable {
    let results: MyResult
    let status: String
}

struct MyResult: Codable {
    let sunrise: String
    let sunset: String
    let solar_noon: String
    let day_length: Int
    let civil_twilight_begin: String
    let nautical_twilight_begin: String
    let nautical_twilight_end: String
    let astronomical_twilight_begin: String
    let astronomical_twilight_end: String
}

Note that I'm not following the video exactly. I took the getData function out of a ViewController class because I didn't think it was relevant--I'm not dealing with any views at this point, and I don't want to be either. I also took the liberty to testing the code in a Swift Playground. I don't know whether that will influence things.

CodePudding user response:

The main issue in your code is your day_length data type. You are trying to decode an Int while the data returned is a String. Besides that it is Swift naming convention to use camelCase to name your struct properties. All you need to do to match your json is to set your JSONDecoder object keyDecodingStrategy property to .convertFromSnakeCase. And when printing the decoding error you should print the error not its localizedDescription as already mentioned in comments:


struct Response: Codable {
    let results: MyResult
    let status: String
}

struct MyResult: Codable {
    let sunrise: String
    let sunset: String
    let solarNoon: String
    let dayLength: String
    let civilTwilightBegin: String
    let nauticalTwilightBegin: String
    let nauticalTwilightEnd: String
    let astronomicalTwilightBegin: String
    let astronomicalTwilightEnd: String
}

Playground testing:

let json = """
{"results":{"sunrise":"12:00:01 AM","sunset":"12:00:01 AM","solar_noon":"9:20:25 AM","day_length":"00:00:00","civil_twilight_begin":"12:00:01 AM","civil_twilight_end":"12:00:01 AM","nautical_twilight_begin":"12:00:01 AM","nautical_twilight_end":"12:00:01 AM","astronomical_twilight_begin":"12:00:01 AM","astronomical_twilight_end":"12:00:01 AM"},"status":"OK"}
"""

do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let result = try decoder.decode(Response.self, from: Data(json.utf8))
    print(result)
} catch {
    print("Decoding error:", error)
}

This will print:

Response(results: MyResult(sunrise: "12:00:01 AM", sunset: "12:00:01 AM", solarNoon: "9:20:25 AM", dayLength: "00:00:00", civilTwilightBegin: "12:00:01 AM", nauticalTwilightBegin: "12:00:01 AM", nauticalTwilightEnd: "12:00:01 AM", astronomicalTwilightBegin: "12:00:01 AM", astronomicalTwilightEnd: "12:00:01 AM"), status: "OK")

  • Related