Search code examples
jsonswiftxcodejsondecoder

Parse More Complex Nested Response


I'm trying parse JSON:

{
  "meta": {
    "page": 1
  },
  "search-results": [
    {
      "id": 41528747
    }
  ]
}

I defined the following structure:

public struct PagedCourses: Codable {

    public struct Meta: Codable {
        public let page: Int

        enum CodingKeys: String, CodingKey {
            case page = "page"
        }
    }

    public struct Course: Codable {
        public let id: Int

        enum CodingKeys: String, CodingKey {
            case id = "id"
        }
    }

    public let meta: Meta
    public let search_results: [Course]
}

When I get data, I get an error.

let courses = try? JSONDecoder().decode(PagedCourses.self, from: data)

I think that the error in the name of the variable 'search_results', but I can not rename it.

How can I parse this data?


Solution

  • Your code can be run with minimal adaptations in a Playground as follows:

    import Cocoa
    
    let jsonData = """
    {
        "meta": {
            "page": 1
        },
        "search-results": [
            {
                "id": 41528747
            }
        ]
    }
    """.data(using: .utf8)!
    
    public struct PagedCourses: Codable {
    
        public struct Meta: Codable {
            public let page: Int
    
            enum CodingKeys: String, CodingKey {
                case page = "page"
            }
        }
    
        public struct Course: Codable {
            public let id: Int
    
            enum CodingKeys: String, CodingKey {
                case id = "id"
            }
        }
    
        public let meta: Meta
        public let searchResults: [Course]
    
        private enum CodingKeys : String, CodingKey {
            case meta
            case searchResults = "search-results"
        }
    }
    
    do {
        let paged = try JSONDecoder().decode(PagedCourses.self, from: jsonData)
        print(paged)
    } catch {
        print(error)
    }
    

    In fact this is the main purpose of the CodingKeys enum, it will allow you to match keys that do not "match" your structs/classes. I still admire the elegance of the Codable protocol which manages to provide this flexibility with minimal overhead and a very readable syntax (and above all: by using simple executable code without resorting to some messy piece of (XML) configuration).