user6354073
user6354073

Reputation:

synchronize async network calls with RxSwift

I am using Facebook to authenticate users. This process happens async. After this is complete i have to authenticate user through firebase, which happens async. Even though I am using RxSwift, I end up nesting async tasks just as if i were to use callbacks and end up with callback hell .

My current procedure just doesn't seem right. Kinda hard to read also. Is it me or is there a more elegant approach to handling multiple async network calls.

for this example I took out the error events because it makes the code even less readable.

Thanks for any tips or guidance.

func rx_login(viewController: UIViewController) {

    /// Facebook login
    rx_facebookLogin(viewController: viewController)
        .asObservable()
        .subscribe(onNext: { [weak self] (credentials: AuthCredential, userInfo: [String: Any]) in

            /// Firebase Login
            rx_firebaseLogin(with: credentials)
                .asObservable()
                .subscribe(onNext: { [weak self] (uid) in

                    /// TODO: Save user info firebase db


                }).addDisposableTo(disposeBag)

        }).addDisposableTo(disposeBag)

Upvotes: 2

Views: 3193

Answers (1)

alephao
alephao

Reputation: 1273

Try using flatMapLatest:

/// Facebook login
rx_facebookLogin(viewController: viewController)
    .flatMapLatest { credentials, _ in rx_firebaseLogin(with: credentials) }
    .subscribe(onNext: { [weak self] (uid) in
        /// TODO: Save user info firebase db
    })
    .addDisposableTo(disposeBag)

To handle the errors, you can use map and filter, eg.:

let facebookLogin = rx_facebookLogin(viewController: viewController)
    .map { credentials, userInfo -> (AuthCredential, String?) in
        let error = userInfo["error"] as? String
        return (credentials, error)
    }
    .shareReplayLatestWhileConnected()

// Success
facebookLogin
    .filter { _, error in error == nil }
    .flatMapLatest { credentials, _ in rx_firebaseLogin(with: credentials) }
    .subscribe(onNext: { (uid) in
        // Success!
    })
    .addDisposableTo(disposeBag)

// Fail
facebookLogin
    .filter { _, error in error != nil }
    .subscribe(onNext: { _, error in
        // Error!
        print(error)
    })
    .addDisposableTo(disposeBag)

Upvotes: 2

Related Questions