
Handling network HTTP response of success data and failure for your Android project using Sandwich.
Requesting data to remote server and handling responses is always one of the important issues in Android development. When we are building our project even a small-sized demo project, we have to spend time constructing the REST service structure. Using the modern Android development tool like Retrofit2, OkHttp, LiveData, or RxJava we can implement the network interfaces easily and request asynchronously. But designing standardized response models/interfaces and handling success data and errors are also important things.

In this post, we’re going to find about how to build a network structure and handle success, failure data from the responses using the Sandwich library.
Including
We should import the dependency of the library to our build.gradle file.
dependencies {
implementation "com.github.skydoves:sandwich:1.0.1"
}
ApiResponse
ApiResponse
is an interface of the retrofit response for handling data and error response with useful transformation extensions. We can get ApiResponse
using the scope extension request
from the Call
.
Let’s see how to get and use the ApiResponse
from the DisneyService.
After getting an instance of the disneyService from the retrofit.create
, we can call the the fetchDisneyPosterList().reqeust
. The reqeust
method receives a lambda function and we can get an instance of theApiResponse
via reqeust
lambda. There are three types of ApiResponse
.
ApiResponse.Success
API success response class from the Retrofit service.
We can get the response body data, StatusCode
, Headers
and etc from the ApiResponse.Success
. If we received 2xx status code from the remote server, we can get the data from the ApiResponse.Success
.
ApiResponse.Failure.Error
API format does not match or applications need to handle errors.
e.g. Internal server error (4xx, 5xx server error).
ApiResponse.Failure.Exception
An unexpected exception occurs while creating the request, processing the response, or parsing error in the client. The problem is the client, so we can’t get an error body or status code. Instead, we can get an exception.
e.g. Network connection error.
ApiResponse Extensions
We can handle response cases more handy using extensions using onSuccess
, onError
, onException
. We can use these scope functions to the ApiResponse
, it reduces the usage of the if/when clause.
ApiErrorModelMapper
Sometimes we have to get our own error response model from the error response. We can map ApiResponse.Failure.Error
model to our customized error model using the mapper. Below example shows how to transform ApiResponse.Failure.Error
to ErrorEnvelope
via ErrorEnvelopeMapper
.
ResponseDataSource
ResponseDataSource
is an implementation of the DataSource
interface. We can bind an instance of the Call to the ResponseDataSource
. The ResponseDataSource
requests asynchronously, and it holds data if the response success. we can observe every response. Also, we can retry fetching data (re-request) if our request got failure.
- Asynchronously send requests.
- A response data holder from the REST API call for caching data on memory.
- Observable for every response.
- Retry fetching data when the request gets failure.
- Concat another
DataSource
and request sequentially.
Combine
Combine a Call
and lambda scope for constructing the DataSource.
Request
Request API network call asynchronously.
If the request is successful, this data source will hold the success response model. In the next request after the success, request() returns the cached API response. If we need to fetch a new response data or refresh, we can use invalidate()
.
dataSource.request()
Retry
Retry requesting API call when the request gets failure.
ObserveResponse
Observes every response data ApiResponse
from the API call request.
dataSource.observeResponse {
Timber.d("observeResponse: $it")
}
Invalidate
Invalidate a cached (holding) data and re-fetching the API request.
dataSource.invalidate()
Concat
Concat an another DataSource
and request API call sequentially if the API call getting successful.
Here is the example of the ResponseDataSource
in the MainViewModel
.
DataSourceCallAdapterFactory
We can get the DataSource
directly from the Retrofit service.
Add a call adapter factory DataSourceCallAdapterFactory
to your Retrofit builder. And change the return type of your service Call
to DataSource
Here is the example of the DataSource
in the MainViewModel.
Handle your network responses more structurally
We looked around into how to build a network structure and handle success, failure data from the responses using the Sandwich library. If you want to get more information about the Sandwich library, you can check the GitHub link :) Thank you!