How do I retrieve data from an API?

I am running the following code and it keeps getting an error saying that found nil while unwrapping an optional. What am I doing wrong? I am using a good API.

Code Block language
class Database_2020 {
static let shared = Database_2020()
var leagueNames: [String]
var leagues: [[String]]
let url = " https://www.someURL.com/service/"
private func getData(from url: String) {
let task = URLSession.shared.dataTask(with: URL(string: url)!) { data, response, error in
guard let data = data, error == nil else
print("something went wrong")
return
}
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.draftPosition)
print(json.results.name)
}
task.resume()
func printData() {
getData(from: url)
}
}



Accepted Reply

Line 19:
Code Block
result = try JSONDecoder().decode(Response.self, from: data)

How is Response defined ?

Replies


an error saying that found nil while unwrapping an optional

Can you tell us on which line you get the error?

As far as I check your code, it has only one forced-unwrapping in this line.
Code Block
let task = URLSession.shared.dataTask(with: URL(string: url)!) { data, response, error in

Then I can find url used in the line above is defined as:
Code Block
let url = " https://www.someURL.com/service/"

This is not a valid URL string, if the leading whitespace actually exists in your code.
Please try removing it:
Code Block
let url = "https://www.someURL.com/service/"


Yes, the leading whitespace had to be removed but now it is executing line 21 - 23. The error is 'The data couldn’t be read because it isn’t in the correct format.'

Thank you for your help.
It looks like the API is in a dictionary? Does that matter on how I format the Struct?

Here is the actual API

Code Block language
https://www.fantasyfootballnerd.com/service/draft-rankings/json/fmt8fvc8xg2s/1/


Line 19:
Code Block
result = try JSONDecoder().decode(Response.self, from: data)

How is Response defined ?

Does that matter on how I format the Struct?

I guess your Response does not match the actual response of the API.

And your code disposes some info of the error.

Change this line:
Code Block
print("failed to convert \(error.localizedDescription)")

to:
Code Block
print("failed to convert \(error)")

And see what's shown.
Response is defined

Code Block language
import Foundation
struct Response: Codable {
    let results: Player_Data
    let status: String
}
struct Player_Data: Codable {
    let playerID: String
    let position: String
    let displayName: String
    let fname: String
    let team: String
    let byeWeek: String
    let standDev: String
    let nerdRank: String
    let positionRank: String
    let overallRank: String
}


The error is

failed to convert keyNotFound(CodingKeys(stringValue: "results", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"results\", intValue: nil) (\"results\").", underlyingError: nil))


The error is

failed to convert keyNotFound(CodingKeys(stringValue: "results", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"results\", intValue: nil) (\"results\").", underlyingError: nil))

The JSON text taken from the URL https://www.fantasyfootballnerd.com/service/draft-rankings/json/fmt8fvc8xg2s/1/ is outlined as:
Code Block
{"PPR":1,"DraftRankings":[...]}

No "results" nor "status" in it.

The URL may be wrong or you may be using the wrong structs for the API.

A JSON-to-code service has shown this Swift code for the JSON text.
Code Block
import Foundation
// MARK: - Response
struct Response: Codable {
let ppr: Int?
let draftRankings: [DraftRanking]?
enum CodingKeys: String, CodingKey {
case ppr = "PPR"
case draftRankings = "DraftRankings"
}
}
// MARK: - DraftRanking
struct DraftRanking: Codable {
let playerId: String?
let position: Position?
let displayName, fname, lname: String?
let team: Team?
let byeWeek, standDev, nerdRank, positionRank: String?
let overallRank: Int?
}
enum Position: String, Codable {
case def = "DEF"
case k = "K"
case qb = "QB"
case rb = "RB"
case te = "TE"
case wr = "WR"
}
enum Team: String, Codable {
case ari = "ARI"
case atl = "ATL"
case bal = "BAL"
case buf = "BUF"
case car = "CAR"
case chi = "CHI"
case cin = "CIN"
case cle = "CLE"
case dal = "DAL"
case den = "DEN"
case det = "DET"
case gb = "GB"
case hou = "HOU"
case ind = "IND"
case jac = "JAC"
case kc = "KC"
case lac = "LAC"
case lar = "LAR"
case lv = "LV"
case mia = "MIA"
case min = "MIN"
case ne = "NE"
case no = "NO"
case nyg = "NYG"
case nyj = "NYJ"
case phi = "PHI"
case pit = "PIT"
case sea = "SEA"
case sf = "SF"
case tb = "TB"
case ten = "TEN"
case was = "WAS"
}