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 NaiveApi
!
Surprise! .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 error.handle()
:
- 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 oferror.handle
).
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 Error
implementations.
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.
Conclusion
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.
Catch the conversation on reddit
Part 1: Api Design — Temporal Coupling
Follow me on Twitter! @zaktaccardi