-3

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 couldnt 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? Thanks in advance

vgvishesh23113
  • 309
  • 3
  • 12
  • This might not be the cause, but the `]age` part looks a little bit suspicious. – Cristik Jan 09 '19 at 12:11
  • Your JSON isn't valid. You should always test your JSON on a validator like [this](https://jsonformatter.curiousconcept.com) before trying to use it. – Dávid Pásztor Jan 09 '19 at 12:13
  • i tried on a json validator and it confirms that this json is in fact valid – vgvishesh23113 Jan 09 '19 at 12:18
  • This part is also not valid: `\"reweries\":[\"id\":1234,\"name\":\"saintArnold\"}`. – Cristik Jan 09 '19 at 12:31
  • **Read** the error message, it's pretty descriptive: Character 64 is the region around `= 38`.Key/value pairs in JSON are always separated by **colon** (`:`). And about 20 characters later there is an opening brace missing after `:[` – vadian Jan 09 '19 at 12:31
  • vadian, there is an opening brace there – vgvishesh23113 Jan 09 '19 at 12:39
  • No, there is none. It must be `...\"reweries\":[{\"id\"...`. By the way there's also a `b` missing, you probably mean `\"breweries\"` – vadian Jan 09 '19 at 12:44
  • Possible duplicate of [How to decode a nested JSON struct with Swift Decodable protocol?](https://stackoverflow.com/questions/44549310/how-to-decode-a-nested-json-struct-with-swift-decodable-protocol) – Hamish Jan 09 '19 at 13:05

2 Answers2

3

Correct json

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

struct Root: Codable {
    let meta: Meta
    let reweries: [Rewery]
}

struct Meta: Codable {
    let page, totalPages, perPage, totalRecords: Int

    enum CodingKeys: String, CodingKey {  // snake case may be used 
        case age = "page"
        case totalPages = "total_pages"
        case perPage = "per_page"
        case totalRecords = "total_records"
    }
}

struct Rewery: Codable {
    let id: Int
    let name: 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\"}]}
"""

  // or 

let jsonNestedString  = """

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


"""

do {

    let jsonData = jsonNestedString.data(using: .utf8)
    let decoder = JSONDecoder()
    let data  = try decoder.decode(Root.self, from: jsonData!)
    print(data)


} catch  {
    print(error)
}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
2

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")])
vadian
  • 274,689
  • 30
  • 353
  • 361