In my app, I have a song-searching feature where I call the Happi API (https://happi.dev/docs/music) and it will return songs with song info that matches a search keyword passed in.
Here is my code for accessing the data:
func getSongs(completion: @escaping(Result<[SongInfo], SongError>) -> Void) {
let dataTask = URLSession.shared.dataTask(with: resourceURL) { data, _, _ in
guard let jsonData = data else {
completion(.failure(.noDataAvailable))
return
}
do {
let decoder = JSONDecoder()
let songResponse = try decoder.decode(SongResponse.self, from: jsonData)
//print("decoded")
let songInfos = songResponse.response.results
completion(.success(songInfos))
}catch{
completion(.failure(.canNotProcessData))
}
}
dataTask.resume()
}
the let dataTask
portion of the code is successful, and does not return the noDataAvailable
error. However, I do receive a canNotProcessData
error when I go decode the JSON data, and I assuming it's because of an error in my structure, but not entirely sure. Here's my structure:
struct SongResponse:Decodable {
var response:Results
}
struct Results:Decodable {
var results: [SongInfo]
}
struct SongInfo:Decodable {
var songName:String
var artist:String
}
Here are photos of my JSON tree from the API:
Essentially, all I want is to retrieve each array in the results:[]
dictionary, then for each array, I want to get the values for track
and artist
. For example in the image there are 5 results, and for each result I want to create a song class with "track" and "artist" attributes. These song classes would be stored in an array. Please let me know how to change my code, or of an easier way to do this!
EDIT: error message:
keyNotFound(CodingKeys(stringValue: "response", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: "response", intValue: nil) ("response").", underlyingError: nil))
Following is the correct structure
do {
let decoder = JSONDecoder()
let songResponse = try decoder.decode(SongResponse.self, from: jsonData)
let songInfos = songResponse.result ?? []
completion(.success(songInfos))
}catch{
completion(.failure(.canNotProcessData))
}
// Models
struct SongResponse: Decodable {
var success: Bool?
var result: [SongInfo]?
}
struct SongInfo: Decodable {
var track: String?
var artist: String?
}