paint-brush
Retrofit Converter for wrapped responsesby@vickyturtle
10,979 reads
10,979 reads

Retrofit Converter for wrapped responses

by Vikas KashyapMay 6th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

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
featured image - Retrofit Converter for wrapped responses
Vikas Kashyap HackerNoon profile picture

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 CustomConverters 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