Many a times API responses are wrapped inside a wrapper class with custom status codes inside the responses. One of the common formats being the following
{"data" : {...}"status_code" : 0"error_message" : null}
If we use the prepackaged json converter (gson/jackson) for retrofit we would have to extract the underlying data object everywhere we make the api calls. This leads to duplication of the data object extraction and error check logic. Something like following
data class Data<T>(var statusCode: Int = 0,var data: T? = null,var message: String? = null)
interface Api {@POST("user/login/")fun login(@Body request: LoginRequest): Single<Data<User>>}
class UserManager {fun login(userName: String, password: String){api.login(LoginRequest(userName, password)).subscribeOn(schedulerProvider.getIoScheduler()).observeOn(schedulerProvider.getUiScheduler()).map {if(it.statusCode ==0) then response.data else throw ApiException(it.error_message)}.subscribe{...}}...
}
Thankfully we can use our own custom converter for retrofit, which would just be a wrapper above the usual Gson Converter, such that this data extraction and error handling logic is handled at one place only. We basically need two classes
CustomConverter
which implements the Retrofit’s Converter<F,T>
interface.CustomConverterFactory
which implements the Retrofit’s Converter#Factory
interface. This is responsible for creating CustomConverter
s for each types.In the above gist we are using the actual converters created by `GsonConverterFactory` only to parse the response, so we don’t have to rewrite any json marshalling code. Our CustomConverter just parses the wrapped class by providing the wrapped `Type` instead of the actual `Type`.
interface Api {@POST("user/login/")fun login(@Body request: LoginRequest): Single<User>}
class UserManager {fun login(userName: String, password: String){api.login(LoginRequest(userName, password)).subscribeOn(schedulerProvider.getIoScheduler()).observeOn(schedulerProvider.getUiScheduler()).subscribe{...}}...
}
This is how our Api interface and logic look like now. Notice the change in return type of the Api interface login method.
Note: This converter assumes that all you responses are in the wrapped format and will fail for any response that comes in unwrapped format