Search code examples
swiftswiftuicombine

Combine and nested JSON objects


I have the following model:

struct Book: Codable, Identifiable {
    var id: Int
    var title: String
    var author: String
}

struct BookWrapper: Codable {
    var books: [Book]

}

and JSON:

{
  "books": [
    {
        "id":     1,
        "title":  "Nineteen Eighty-Four: A Novel",
        "author": "George Orwell"
    }, {
        "id":     2,
        "title":  "Animal Farm",
        "author": "George Orwell"
    }
  ],
  "errMsg": null
}

I'm trying to grab data using Combine, but cannot find a way how to go around that books array. In case of flat data I would use following:

func fetchBooks() {
        URLSession.shared.dataTaskPublisher(for: url)
            .map{ $0.data }
            .decode(type: [Book].self, decoder: JSONDecoder())
            .replaceError(with: [])
            .eraseToAnyPublisher()
            .receive(on: DispatchQueue.main)
            .assign(to: &$books)
    }   

I tried to use BookWrapper.self, but it doesn't make sense. Is there any elegant way how to solve it?


Solution

  • You can just map the books property of BooksWrapper before it gets to your assign:

    func fetchBooks() {
        URLSession.shared.dataTaskPublisher(for: url)
            .map{ $0.data }
            .decode(type: BookWrapper.self, decoder: JSONDecoder())
            .replaceError(with: BookWrapper(books: [])) //<-- Here
            .map { $0.books }  //<-- Here
            .receive(on: DispatchQueue.main)
            .assign(to: &$books)
    }