2

I have a particular situation where the returning function provides something like AnyPublisher<Response, Error>. But from the calling function, I want to return AnyPublisher<Response, Never>.

//just an example
func getList(_ request: QueryRequest) -> AnyPublisher<Response, Never> {
   return executeQuery(request).eraseToAnyPublisher()
}

func executeQuery(_ request: QueryRequest) -> AnyPublisher<Response, Error> {
   return someData().eraseToAnyPublisher()
}

When I do this, I am getting Cannot convert return expression of type 'AnyPublisher<Response, Error>' to return type 'AnyPublisher<Response, Never>'

How do I do convert to AnyPublisher<Response, Never> without modifying the called function?

Note: I cannot modify the called function's return type as it's used by other methods which make use of Error

Nibin V
  • 474
  • 6
  • 24
  • 1
    Depends on what you want to do when an error arrives from `executeQuery`. Do you ignore and complete, do you replace it with some value and complete? – New Dev Dec 07 '20 at 05:16
  • I want to ignore and continue, in case an error occurs for this one. – Nibin V Dec 07 '20 at 05:36
  • What does continue mean? If `executeQuery` sends an error, its publisher is done. You can retry (which would resubscribe), and depending on what it does, it might execute another query. But then there are more questions... how many times to retry? Do you wait between retries? – New Dev Dec 07 '20 at 05:37
  • In this particular case, I am not expecting an error. But however, if I ever receive one is there a way I can handle it in `getList` itself and return `AnyPublisher`? – Nibin V Dec 07 '20 at 05:43
  • If you're not expecting an error, you can use `.assertNoFailure("wtf?")` - which would result in a fatal error if there was an failure sent from upstream... Again, depends on what "handle" the error means – New Dev Dec 07 '20 at 05:45
  • What about this one - if I ever receive one is there a way I can handle it in getList itself and return AnyPublisher? – Nibin V Dec 07 '20 at 05:47
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/225604/discussion-between-nibin-v-and-new-dev). – Nibin V Dec 07 '20 at 05:53
  • Does this answer your question? [Combine: how to replace/catch an error without completing the original publisher?](https://stackoverflow.com/questions/58675235/combine-how-to-replace-catch-an-error-without-completing-the-original-publisher) – Nikolai Dec 07 '20 at 06:09

1 Answers1

1

To convert from an upstream publisher that can fail to one that never fails, you need to decide how to handle a case when an error does occur (since it cannot be sent to your downstream).

If you "know" that it will never occur in your specific case, you can assert that there won't be an error:

return executeQuery(request)
          .assertNoFailure("this shouldn't have happened")
          .eraseToAnyPublisher()

Or you can just ignore it (by catching and replacing it with an Empty publisher) , which would complete your pipeline:

return executeQuery(request)
          .catch { _ in Empty<Response, Never>() }
          .eraseToAnyPublisher()

You can also replace an error with some value with .replaceError(with:)

Note, that when there is an error from executeQuery publisher (the upstream), it completes the pipeline, so your downstream will receive a completion as well.

You can't continue to receive values from an errored-out upstream, as you asked about in comments. You might consider re-subscribing with .retry if you believe the error was transient (e.g. server is unreachable)

New Dev
  • 48,427
  • 12
  • 87
  • 129