Issue #451
For some services, we need to deal with separated APIs for getting ids and getting detail based on id.
To chain requests, we can use flatMap and Sequence, then collect to wait and get all elements in a single publish
Transforms all elements from an upstream publisher into a new or existing publisher.
struct FlatMap<NewPublisher, Upstream> where NewPublisher : Publisher, Upstream : Publisher, NewPublisher.Failure == Upstream.Failure
A publisher that publishes a given sequence of elements.
struct Sequence<Elements, Failure> where Elements : Sequence, Failure : Error
func fetchItems(completion: @escaping ([ItemProtocol]) -> Void) {
requestCancellable = URLSession.shared
.dataTaskPublisher(for: topStoriesUrl())
.map({ $0.data })
.decode(type: [Int].self, decoder: JSONDecoder())
.flatMap({ (ids: [Int]) -> AnyPublisher<[HackerNews.Item], Error> in
let publishers = ids.prefix(10).map({ id in
return URLSession.shared
.dataTaskPublisher(for: self.storyUrl(id: id))
.map({ $0.data })
.decode(type: HackerNews.Item.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
})
return Publishers.Sequence<[AnyPublisher<HackerNews.Item, Error>], Error>(sequence: publishers)
// Publishers.Sequence<[AnyPublisher<HackerNews.Item, Error>], Error>
.flatMap({ $0 })
// Publishers.FlatMap<AnyPublisher<HackerNews.Item, Error>, Publishers.Sequence<[AnyPublisher<HackerNews.Item, Error>], Error>>
.collect()
// Publishers.Collect<Publishers.FlatMap<AnyPublisher<HackerNews.Item, Error>, Publishers.Sequence<[AnyPublisher<HackerNews.Item, Error>], Error>>>
.eraseToAnyPublisher()
// AnyPublisher<[HackerNews.Item], Error>
})
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
.sink(receiveCompletion: { completionStatus in
switch completionStatus {
case .finished:
break
case .failure(let error):
print(error)
}
}, receiveValue: { items in
completion(items)
})
}
Start the conversation