-1

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?

nik3212
  • 392
  • 1
  • 6
  • 18
  • When asking questions on StackOverflow you should always strive to provide executable code, in Swift this is best done as a Playground. You should also print out the error you get which in this case would be `keyNotFound(__lldb_expr_1.PagedCourses.(CodingKeys in _63370E247A5AFC0F0F23D40800403DB3).search_results, Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key search_results (\"search_results\").", underlyingError: nil))` confirming your suspicion. Luckily you _can_ do something about this as shown in my answer. – Patru Apr 27 '18 at 00:25

1 Answers1

1

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).

Patru
  • 4,481
  • 2
  • 32
  • 42