6

I want to get data from REST API and in order to do that, I need to first get an array of IDs - 1st call. After that, I need to do an API call using each ID. I don't want to use completionHandlers but Combine. I started with dataTaskPublishers but I am not sure how can I chain them to work properly

Here is my code so far:

   private func getIDs(for type: DataType) -> AnyPublisher<[ID], Error> {
        guard let url = URL(string: "url")
            else { fatalError("Wrong URL") }

        return session.dataTaskPublisher(for: url)
            .receive(on: RunLoop.main)
            .map { $0.data }
            .decode(type: [ID].self, decoder: decoder)
            .eraseToAnyPublisher()
    }

    private func getData(with id: ID) -> AnyPublisher<MyData, Error> {
        guard let url = URL(string: "url_with_id")
            else { fatalError("Wrong URL") }
        return session.dataTaskPublisher(for: url)
            .receive(on: RunLoop.main)
            .map { $0.data }
            .decode(type: MyData.self, decoder: decoder)
            .eraseToAnyPublisher()
    }

I am not really sure how can I connect them to get something that is assignable to my state variable - array of MyData.

czater
  • 377
  • 4
  • 11
  • Actually I think it's simplest to use `zip` for this, unless I've misunderstood the question. – matt Dec 14 '19 at 20:58

1 Answers1

2

As suggested in https://stackoverflow.com/a/56786412/1271826, you can use collect():

func getAllData(for type: DataType) -> AnyPublisher<[MyData], Error> {
    getIDs(for: type).flatMap { ids in
        Publishers.Sequence(sequence: ids.map { self.getData(with: $0) })
            .flatMap { $0 }
            .collect()
    }.eraseToAnyPublisher()
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • 1
    Why not use `return Publishers.MergeMany(publishers).eraseToAnyPublisher()` in the `flatMap` block instead? – jjatie Dec 31 '19 at 11:06