Swift Combine: How to handle event and continue stream

Viewed 3784

I am implementing a library with a Login function using Swift Combine.

With the following code, I am already able to login, serialize the response to an object AuthenticationResult, and return a Publisher with a User or ApiError as a result.

As part of the response (AuthenticationResult object), I am also getting an accessToken from the API. I would like to save that token locally as part of this stream. But I would like that to be done internally in the library, so that the response from the login function does not change.

Is there a way to handle this type of situations in the stream, to handle the event but then to continue with the stream to return an User?

func authenticate(username: String, password: String) -> AnyPublisher<User, ApiError> {
    let parameters: [String: Any] = [
        "username": username,
        "pw": password
    ]

    var request = URLRequest(endpoint: Endpoint.login)
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: [])

    return URLSession.shared.dataTaskPublisher(for: request)
        .map { $0.data }
        .decode(type: AuthenticationResult.self, decoder: JSONDecoder())
        .map { $0.user }
    // Here I would like to do something like: .handleAndContinue { self.save($0.accessToken }
        .mapError { _ in ApiError.loginError }
        .receive(on: RunLoop.main)
        .eraseToAnyPublisher()
}

Or is there any other way to handle this type of situations with Swift Combine?

1 Answers

That can be done with:

        .handleEvents(receiveOutput: {
            self.save($0.accessToken)
        })
Related