-2

I was trying to parse some JSON data but had some trouble. Here is the JSON:

    {
  "result": {
    "artist": {
      "name": "The Beatles"
    },
    "track": {
      "name": "Yesterday",
      "text": "[Verse 1]\nYesterday\nAll my troubles seemed so far away\nNow it looks as though they're here to stay\nOh, I believe in yesterday\n\n[Verse 2]\nSuddenly\nI'm not half the man I used to be\nThere's a shadow hanging over me\nOh, yesterday came suddenly\n\n[Chorus]\nWhy she had to go\nI don't know, she wouldn't say\nI said something wrong\nNow I long for yesterday\n\n[Verse 3]\nYesterday\nLove was such an easy game to play\nNow I need a place to hide away\nOh, I believe in yesterday\n\n[Chorus]\nWhy she had to go\nI don't know, she wouldn't say\nI said something wrong\nNow I long for yesterday\n\n[Verse 4]\nYesterday\nLove was such an easy game to play\nNow I need a place to hide away\nOh, I believe in yesterday",
      "lang": {
        "code": "en",
        "name": "English"
      }
    },
    "copyright": {
      "notice": "Yesterday lyrics are property and copyright of their owners. Commercial use is not allowed.",
      "artist": "Copyright The Beatles",
      "text": "All lyrics provided for educational purposes and personal use only."
    },
    "probability": "75.00",
    "similarity": 1
  }
} 

And here is my code so far:

        guard let url = URL(string: "https://orion.apiseeds.com/api/music/lyric/Beatles\Yesterday?apikey=xxx") else { return }

        URLSession.shared.dataTask(with: url) { (data, response, error) in

            if error != nil {

                print(error!)
            }

            guard let data = data else { return }
            do {

                let data = try JSONDecoder().decode(Result.self, from: data)
                print(data)
            } catch let jsonError {

                print(jsonError)
            }
        }.resume()

struct Result: Codable {

    let artist: [Artist]
}

struct Artist: Codable {

    let name: String
}

The error that I get when I try to run it is:

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

All I would like to do is get the lyrics from the song. Please could someone look at this as I am struggling quite a lot.

LinusGeffarth
  • 27,197
  • 29
  • 120
  • 174
  • "artist" in a *Result* is not an array, but an object. Change Result to have *let artist: Artist* – muvaaa May 28 '18 at 09:12
  • I just tried. Here is the error:keyNotFound(CodingKeys(stringValue: "artist", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"artist\", intValue: nil) (\"artist\").", underlyingError: nil)) –  May 28 '18 at 09:15
  • Also "result" is not top level. You should have some *Codable* that wraps result, as it is in the json: ```struct ResultResponse: Codable { let result: Result }``` – muvaaa May 28 '18 at 09:23
  • Please most that as an answer as it works! –  May 28 '18 at 09:29

2 Answers2

3

Create a proper struct for your model if something comes with a nil, make it optional otherwise it will crash, to convert JSON to Objects you can use this online tool for the future, is quite useful! https://app.quicktype.io/

struct AudioSearch: Codable {
    let result: Result
}

struct Result: Codable {
    let artist: Artist
    let track: Track
    let copyright: Copyright
    let probability: String
    let similarity: Int
}

struct Artist: Codable {
    let name: String
}

struct Copyright: Codable {
    let notice, artist, text: String
}

struct Track: Codable {
    let name, text: String
    let lang: Lang
}

struct Lang: Codable {
    let code, name: String
}

And use the decode like this:

let result = try JSONDecoder().decode(AudioSearch.self, from: data)
1

You should create struct like below for your JSON,

struct ResultResponse: Codable {
    let result: Result
}

struct Result: Codable {
    let artist: Artist
    let track: Track
    let copyright: Copyright

    let probability: String
    let similarity: Int
}

struct Artist: Codable {
    let name : String
}

struct Track: Codable {
    let lang: Language

    let name: String
    let text: String
}

struct Language: Codable {
    let code: String
    let name: String
}

struct Copyright: Codable {
    let notice:String
    let artist: String
    let text: String
}

Parse it like below,

let result = try JSONDecoder().decode(ResultResponse.self, from: data)

Whenever you have any doubt creating JSON Codable, You can create Codable from json4swift. Paste your valid JSON String and it will create Codable objects for you.

app.quicktype.io is nice solution to create Codable for your JSON.

PPL
  • 6,357
  • 1
  • 11
  • 30