API Design — Handling exceptions
Design for errors, report defects
There are two kinds of exceptions.
- Errors — expected states that we can design for
- ex: device not connected to internet
- ex: user provided incorrect credentials
- Defects — unexpected states that the application does not know how to handle. These are bugs that developers failed to account for. Report them or better yet, crash the application to increase the chances that this defect does not make it to production. Log statements are easily missed when your UI fails silently.
Design for errors by building them into the return values of our APIs (methods)
The Naive API
Let’s use our
.login(credentials) threw an exception because we provided the wrong credentials. How can we improve this?
The Better API
What is a
LoginResponse? It represents all possible outcomes of a login request. Let’s dig deeper:
Usage now becomes:
Handling different types of errors
Let’s take a look at what the
Error object really is.
The application could:
- try again in when the device regains connectivity
- prompt the user to enter correct credentials.
Here’s usage of the
BetterApi that accounts for different types of errors.
The developer passes the following to
- 3 separate functions able to handle each of the 3 error types
- Only the function that map to the actual error type will be called. If the error is an instance of
invalidCredentials, then only its function will be called (first parameter of
The static extension method
error.handle() enforces type safety as well. What does it look like?
Additional benefit: extra resilience to adding new implementations of
Bonus points: Kotlin Sealed Classes
One of the Kotlin’s best features is its
sealed classes, which can give us compile time type-safety.
Usage now becomes:
More Bonus Points: Rx
With proper dependency management and scoping, you can expose all login attempts as observables for easy consumption from your UI.
Building errors into the return value of API calls makes all possibilities more obvious to the developer, allowing the application to robustly handle each scenario.
Shoutout to Paco Estevez who got me to really think about this.
Source is available on GitHub.