Search code examples
iosjsonswiftcodable

How to parse nested JSON in swift?


I have a local JSON string and I am trying to parse it, but when I try to do so, I am constantly getting an error. I have also seen this error in nested dictionary but couldn't find an error. Below is the JSON string:

let jsonNestedString  = "{\"meta\":{\"page\":1,\"total_pages\":4,\"per_page\":10,\"total_records\" : 38}, \"reweries\":[\"id\":1234,\"name\":\"saintArnold\"},{\"id\":52892,\"name\":\"buffalo bayou\"]}"

I am doing this process via Codable and below is the struct I have created for the same:

struct PagedBreweries:Codable{
    struct Meta:Codable{
        let page : Int
        let total_pages:Int
        let per_page:Int
        let total_records: Int
        enum CodingKeys: String, CodingKey{
            case page
            case total_pages
            case per_page
            case total_records
        }
    }
    
    struct Brewery :Codable{
        let id:Int
        let name:String
        
    }
    let meta:Meta
    let breweries :[Brewery]
}

then this data is parsed to a function as below:

    func jsonNested(){
    let jsonData = jsonNestedString.data(using: .utf8)
    let decoder = JSONDecoder()
    let data  = try! decoder.decode(PagedBreweries.Meta.self, from: jsonData!)
    print(data)
}

and when I try to build, the error I get is present in try! decoder.decode
command and the error is:

Thread 1: Fatal error: 'try!' expression unexpectedly raised an error:
Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "page", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: "page", intValue: nil) ("page").", underlyingError: nil))

Could any one provide a solution?


Solution

  • The JSON is corrupt and you are decoding the wrong root object.

    This is the correct JSON being decoded with your structs and conforming to the Swift naming convention

    let jsonNestedString  = """
    {"meta":{"page":1,"total_pages":4,"per_page":10,"total_records" : 38}, "breweries":[{"id":1234,"name":"saintArnold"},{"id":52892,"name":"buffalo bayou"}]}
    """
    
    struct PagedBreweries : Codable {
        struct Meta : Codable {
            let page : Int
            let totalPages:Int
            let perPage:Int
            let totalRecords: Int
        }
    
        struct Brewery : Codable {
            let id:Int
            let name:String
    
        }
        let meta:Meta
        let breweries :[Brewery]
    }
    
    func jsonNested(){
        let jsonData = Data(jsonNestedString.utf8)
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        let data  = try! decoder.decode(PagedBreweries.self, from: jsonData)
        print(data)
    }
    
    jsonNested()
    
    // Printed result: 
    // PagedBreweries(meta: __lldb_expr_1.PagedBreweries.Meta(page: 1, totalPages: 4, perPage: 10, totalRecords: 38), breweries: [__lldb_expr_1.PagedBreweries.Brewery(id: 1234, name: "saintArnold"), __lldb_expr_1.PagedBreweries.Brewery(id: 52892, name: "buffalo bayou")])