Search code examples
jsonswiftswift5

parsing nested JSON in Swift 5


Can't figure out how to build the struct for this nested JSON. I'm so close but missing something..

I'm trying to verify I'm loading correctly... the first two work great the nested data fails

print(json.pagination.items) // this works
print(json.releases[3].date_added) // this works 
print(json.releases[3].basicInformation?.year) //NOT WORKING, returns nil

here is the struct in built

struct Response: Codable {
    let pagination: MyResult
    let releases: [MyReleases]
}

struct MyResult: Codable {
    var page: Int
    var per_page: Int
    var items: Int
}

struct MyReleases: Codable {
    var date_added: String
    let basicInformation: BasicInformation?
}

struct BasicInformation: Codable {
    let title: String
    let year: Int

    enum CodingKeys: String, CodingKey {
        case title, year
    }
}

My JSON is

{
   "pagination":{
      "page":1,
      "pages":2,
      "per_page":50,
      "items":81,
      "urls":{
         "last":"https://api.discogs.com/users/douglasbrown/collection/folders/0/releases?page=2&per_page=50",
         "next":"https://api.discogs.com/users/douglasbrown/collection/folders/0/releases?page=2&per_page=50"
      }
   },
   "releases":[
      {
         "id":9393649,
         "instance_id":656332897,
         "date_added":"2021-03-28T10:54:09-07:00",
         "rating":2,
         "basic_information":{
            "id":9393649,
            "master_id":353625,
            "master_url":"https://api.discogs.com/masters/353625",
            "resource_url":"https://api.discogs.com/releases/9393649",
            "thumb":"",
            "cover_image":"",
            "title":"Ten Summoner's Tales",
            "year":2016
         }
     }
     ]
}

Any help would be greatly appreciated. I'm so close but missing something... :(


Solution

  • First of all

    json.releases[3].date_added
    

    doesn't work with the given JSON, it will crash because there is only one release.


    In MyReleases you have to add CodingKeys to map the snake_case name(s)

    struct MyReleases: Codable {
        var dateAdded: String
        let basicInformation: BasicInformation?
    
        private enum CodingKeys: String, CodingKey {
            case basicInformation = "basic_information", dateAdded = "date_added"
        }
    }
    

    or add the .convertFromSnakeCase key decoding strategy.

    You can even decode dateAdded as Date with the .iso8601 date decoding strategy.