At a company that I have worked in the past, a high-traffic online classifieds, the backend was transitioning from a monolithic architecture, to a micro-services one.
At the time I joined, the apps had to consume some endpoints from the legacy (monolith) backend, and some endpoints already migrated to the new backend. For example, getting the User’s details were on the old one, but getting the favorited items were on the new one.
The backend engineers haven’t considered the creation of a single interface in order to handle the login in both architectures, meaning the apps needed to authenticate the user into both backends independently.
Furthermore, the access token returned from the legacy backend, had to be sent as a parameter when authenticating on the new backend.
The existing implementation, using
We decided to rebuild the flow from scratch using , because provided an easy way to chain async network requests, map responses into another observable, handle error scenarios, and unit test using & .
We were already using RxSwift in other parts of the app.
If you are unfamiliar with Reactive Programming, I recommend this article:
One important consideration we had to take into account, is the fact that both requests need to succeed in order to update the app state. If either of the auth requests fails, the whole login operation is considered as failed.
The flowchart is pretty straightforward:
Authentication in both backends needs to succeed
Let’s start by creating a protocol to authenticate using Username and Password.
This is the only method that will be exposed from the network layer. It will return a
Single of type
Single is basically an observable that can emit either one value or error.
Then we create private methods to authenticate on each backend, and a private method to store locally the tokens:
Finally, with the private methods in place, we can write the body of the public method
authenticate(username: String, password: String)
The implementation looks clean and easy to understand thanks to
Void value. Any error returned by any of the private methods will be surfaced and stop the execution of the following chained methods. Therefore, the subscriber can be configured as follow:
I mentioned before that any error returned by the private methods (eg: network error, server error, validation error) will be surfaced and ultimately returned to the client consuming the protocol
However it is possible that for simplicity and/or to hide internal behaviour, we want to just map the internal error to another.
We can achieve that using the operator
Reactive programming is a broadly used paradigm, as an alternative to Imperative programming, because provides an easier way to handle async calls, manipulate the results through the large number of, and a cleaner code organization.
A disadvantage of using 3rd party libraries likeor , is that your code will be depending on the evolution of the library, that is embedded in several layers of your app, and it’s going to be a non-trivial task if you decide to use another paradigm, or replace the existing library for another.
The new frameworkintroduced in the WWDC19 by Apple, proposes a native solution to reactive programming, and an alternative to the 3rd party libraries mentioned above.