Supercharging Retrofit with Generics, Adapters & Callbacks
Supercharging Retrofit with Generics, Adapters & Callbacks
Retrofit is a great type-safe client for web APIs. Using it is easy and it ‘just works’. However, many times you’ll come to a point where the default enqued callback handler interface doesn’t quite meet your needs, for various reasons:
- Code Quality, Maintainability & Readability
- When the Response<T> is unsuccessful (not having 2xx code), the response body is not deserialized automatically. This backfires a lot because many web-apps have a specific structure for almost all requests, similar to what you see in Google’s sample new architecture components app, right here.
- Sometimes, you don’t want to handle ALL the cases for a call. For example, you could only check failures, access forbidden/denied or server error cases.
- In many cases, a specific part of your callback does some things on every case.
A solution
We need to define our own callback interface(s). Here are some that I made myself to suit my (and I hope, many of your’s as well), needs:
Of course, you can implement some as functional interfaces with lambdas, or choose to override more methods at will, without changing the callback type, easily.
Now that this part of the problem is solved, a way must be found to make retrofit’s callbacks compatible with our own. That rings the ‘programming patterns’ bell; we shall create an adapter. It is going to implement the Callback<T>, but with an ApiResponse<K> as T. Afterwards, it’s going to call the proper callback methods, depending on the response code. If the response code is not 2xx, it’s also going to try to deserialize the response on it’s own (be careful here: if the response needs a custom Gson() instance, you’ve got to pass (or inject) your own as well. This is usually not needed and considered as a bad practice though. A simple list of errors could be returned for example, or just collections of primitives, nothing that needs complex deserialization like Joda’s DateTime for example).
Here’s the code:
Of course, you can tailor this to your own needs. All code in this article is available under the MIT License.
Ι’m open to recommendations and feedback so, please leave a comment, clap if you liked it, share it with your developer-friends.