0

This is a continuation of my previous question Parse decodable struct property as any data type

I have a funciton that goes and gets data from an API and decodes this JSON to an NbaJsonData type

func getTeamGameLog(teamId: Int) async throws -> NbaJsonData {
    
    // This will need to be retrieved from somewhere else, as this will change over time
    let season = "2022-23"
    
    let urlStr = "https://stats.nba.com/stats/teamgamelog?DateFrom=&DateTo=&LeagueID=00&Season=\(season)&SeasonType=Regular%20Season&TeamID=\(teamId)"
    let url = URL(string: urlStr)
    
    var request = URLRequest(url: url!)
    request.httpMethod = "GET"
    request.setValue("stats.nba.com", forHTTPHeaderField: "host")
    request.setValue("https://www.nba.com/", forHTTPHeaderField: "Referer")
    request.setValue("https://www.nba.com", forHTTPHeaderField: "Origin")
    request.setValue("application/json", forHTTPHeaderField: "Accept")
    
    let (data, _) = try await URLSession.shared.data(for: request)
    return try (JSONDecoder().decode(NbaJsonData.self, from: data))
}

NbaJsonData looks like this, where ResultSet is an enum

struct NbaJsonData: Decodable {
    var resultSets: [ResultSet]
}

and

enum ResultSet: Decodable {
    
    case lastMeeting([LastMeeting])
    case lineScore([LineScore])
    case teamGameLog([TeamGameLog])
    case string([String]) // A catch-all for arrays we don't need.
    
    enum CodingKeys: CodingKey {
        case name
        case headers
        case rowSet
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // Decoding must be done in the order the data arrives
        // 1, "two" => Int.self, String.self... etc.
        let name = try container.decode(String.self, forKey: .name)
        _ = try container.decode([String].self, forKey: .headers)
        // rowSet can be any type, but the type is inferred from the resouce "name".
        // We don't want it to throw, so for now, set an empty array for everything else
        switch name {
        case "GameHeader",
            "AvailableVideo":
            self = .string([String]()) // Set an empty array, we don't need them yet
            
        case "TeamGameLog":
            self = .teamGameLog(try container.decode([TeamGameLog].self, forKey: .rowSet))
            
        case "LineScore":
            self = .lineScore(try container.decode([LineScore].self, forKey: .rowSet))
            
        case "LastMeeting":
            // Decode it as a LastMeeting object
            self = .lastMeeting(try container.decode([LastMeeting].self, forKey: .rowSet))
            
        default:
            // Nothing to parse
            throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: "Unknown resource name \(name)"))
        }
    }
}

Now, this works okay, and calling the getTeamGameLog function works, and I can see the output in the debugger, but the problem I now have is accessing that data, so I want to do something like this

let data = try await getTeamGameLog(teamId: team.id)
let resultSet = data.resultSets[0] // This is an enum result, and is an array
// foreach teamGameLog in resultSet

resultSet does show the data in the debugger, but I don't know how to parse what's in it as a type

enter image description here

The highlighted gameId property is what I'm trying to access.

enter image description here

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52

0 Answers0