Supercharging Retrofit with Kotlin
Published on: 28:01:2019.
This works, but there’s a few rough edges:
- Our API isn’t declarative. To determine what state we’re in we have to null check a bunch of things and it’s easy to miss a case
- We’ve inadvertently leaked our network serializer (moshi) into our application layer to deserialize error bodies
- Streams get torn down when a network error occurs. This isn’t a big deal here, but if we start combining network streams with other Observables we likely don’t want network errors to terminate the resulting stream
To have Retrofit return an instance of NetworkResponse when the getTokens() API is invoked, we have to write a custom CallAdapter.Factory. The CallAdapter.Factory below says, “I know how to create instances of NetworkResponse that are emitted to RxJava streams."
When the getTokens() API is invoked, this CallAdapter.Factory:
- Delegates to an adapter that knows how to make an instance of the type Observable<AccessToken> (line 46)
- Asks for a converter capable of serializing the type Error (line 54)
- Creates a KotlinRxJava2CallAdapter (line 60). This adapter deserializes error bodies and will decorate the stream of Observable<AccessToken> into a Single<NetworkResponse<AccessToken,Error>>
To use our custom CallAdapter.Factory we have to plug it into our Retrofit instance. Adapter registration order is important since we’ve written a delegating CallAdapter; we must register our adapter before any other adapters it may delegate to. In the snippet below we delegate the creation of Observable<AccessToken> to Square’s RxJava Adapter.
val retrofit = Retrofit.Builder()
If you’re interested in having a Kotlin-esque API to the wire that provides error body deserialization, you can find the full code for our Adapter here.
P.S. We’re hiring!