Loading...
Home
  • Tech Blogs
  • Videos
  • Conferences
    • Droidcon News
    • Upcoming Conferences
    • Become a Partner
    • Past Events
    • Keep Me Informed
    • Diversity Scholarships
  • Community
    • droidcon Team
    • How to Hold a Droidcon
  • Android Careers
Sign In

Global CSS

 

Handling success data and error callback responses from a network for Android projects using Sandwich

 

 
Jaewoong Eum
A software engineer: Android, IoT. Interested in Psychology, Magic Tricks, and writing poems. https://github.com/skydoves 
Published: January 28, 2021
Tweet
Share
 

 

In modern Android development, constructing network structure is an important factor and we can implement network communication structure using HTTP client tools like OkHttp, Retrofit, or Volley. Also, it is an important factor to design how to handle callback responses from the network. Many people standardize callback responses by creating wrapper classes like Resource, Result, or Response and handling success data or error messages depending on the response state like the below.

 

 

However, what if we want to handle error cases depending on its HTTP status code (401, 402. 403..) or handle each error response globally for logging/debugging error messages or showing toasts? Or what if we want to get directly typed wrapper classes from every different service without creating new instances of wrappers every time manually? Probably we have to write a bunch of codes and classes for building the response handling. Constructing the structure of the standardized response requires a lot of resources at the initial time. In this post, we will take a look at how to handle responses and reduce our setup time for standardizing callbacks using a library Sandwich.

 

Image for post

Sandwich

 

Sandwich was invented for constructing a standardized interface of the response from the network callback communication. It helps to reduce our construction time and makes focus us on business logic. We can handle success data, error responses, and exceptional cases intuitively using useful extensions of the interface.

Moreover, Sandwich supports handling error responses globally, Mapper, Operator, and great compatibilities with modern Android like LiveData, coroutines, and flow.

 

Image for post

 

Sandwich has been downloaded in more than 50K around the world!

 

Including

To use this library, we should add its dependency to our build.gradle file. And you can check out the recent version here.

 

 

ApiResponse

ApiResponse is an abstract for constructing standard responses from the response of the retrofit call. It provides useful extensions for handling success data, error responses, and exceptional cases. We can get ApiResponse using extensions from an instance of Call or we can just set it as a response type on the suspend function using coroutines. There are three types of the ApiResponse.

 

ApiResponse.Success

A standard success response class that inherits ApiResponse. We can get body data of the response, StatusCode, Headers , and more details about the network callback response.

 

 

ApiResponse.Failure.Error

A standard error response class that inherits ApiResponse. API communication conventions are not matched or applications need to handle errors. e.g., internal server error. We can get a ResposeBody, StatusCode, Headers, and more details about the error response.

 

 

ApiResponse.Failure.Exception

A standard exceptional response class that inherits ApiResponse. An unexpected exception occurs while creating requests or processing a response on the client-side. e.g., Network connection error. We can get an exception message from this response.

 

How to get ApiResponse

We can get ApiRespose from the Retrofit call in two ways.

  • Using Coroutines (set ApiResponse<T> as a return type of a suspend function)
  • Using request extension on an instance of the Call.

 

Using coroutines

We can use suspend keyword in our Retrofit services and setApiResponse<T>as a response type. Build your Retrofit using the CoroutinesResponseCallAdapterFactory call adapter factory.

 

 

We should make Retrofit service functions as suspension functions using the suspend keyword. And we can set ApiResponse<T> as a response type. So we can get the ApiResponse from the Retrofit service call, and handle them right away using extensions.

 

 

And we can get ApiResponse<MODEL> and handle responses depending on its state using extensions. (onSuccess, onError, onException) By using those scope extensions, we don’t need to check type using exhaustive when-statement or if-else statement. If we want to handle only the success case, we can omit the other extensions. (onError, onException) The opposite case is similar.

 

 

Or we can emit success data in Flow using suspendOnSuccess like the below. If we want to use suspension functions in the response handling scopes, we can use suspendOnSuccess, suspendOnError, suspendOnException instead. This is useful to use on repository pattern for emitting flow data to ViewModel.

 

 

Using Call instance

If you are not a coroutines user, we can get ApiResponse from an instance of Call using request extension.

 

 

Mapper

Mapper is useful when we want to transform ApiResponse.Success or ApiResponse.Failure.Error to our custom model in our ApiResponseextension scopes.

 

ApiSuccessModelMapper

We can map the ApiResponse.Success model to our custom model using the ApiSuccessModelMapper<T, R> and map extension. We should create a custom mapper that inherits ApiSuccessModelMapper for converting the original ApiResponse.Success model to our custom model.

 

 

We can use the map extension with a lambda.

 

 

If we want to get a converted data in the lambda scope, we can give the mapper as a parameter for the onSuccess or suspendOnSuccess.

 

 

ApiErrorModelMapper

We can map the ApiResponse.Failure.Error model to our custom error model using the ApiErrorModelMapper<T> and map extension.

 

 

If we want to get the transformed data from the start in the lambda, we can give the mapper as a parameter for the onError or suspendOnError.

 

 

Operator

We can delegate the onSuccess, onError, onException using the operatorextension and ApiResponseOperator. The Operator is very useful if we want to handle ApiResponses standardly or reduce the role of the ViewModel and Repository. Here is an example of standardized error and exception handling. For example, we can create an operator CommonResponseOperatorfor handling error cases and exceptional cases. We will handle success responses manually.

 

 

And we can use it on the ApiResponse using operator extension.

 

 

Operator for coroutines

If we want to operate and delegate a suspension lambda to the operator, we can use the suspendOperator extension and ApiResponseSuspendOperatorclass. For example, we can create an operator CommonResponseOperatorextends ApiResponseSuspendOperator with suspend override methods.

 

 

And we can use suspension functions like emit in the success lambda.

 

 

Global operator

We can operate an operator globally all ApiResponses in our application using SandwichInitializer. So we don't need to create every instance of Operators or use dependency injection for handling common operations. Here is an example of handling a global operator of ApiResponse.Failure.Error and ApiResponse.Failure.Exception. In this example, We will handle ApiResponse.Success manually.

 

Application class

We can initialize the global operator on the SandwichInitializer.sandwichOperator. It is recommended to initialize it in the Application class.

 

 

GlobalResponseOperator

The GlobalResponseOperator can extend any operator classes. (ApiResponseSuspendOperator or ApiResponseOperator)

 

 

ViewModel/Repository

We don’t need to use the operator expression anymore. Because we set the global operator via the SandwichInitializer . The global operator will be operated automatically on each ApiResponses, so we should handle only the successful case.

 

 

Merge

We can merge multiple ApiResponses as one ApiResponse depending on the policy. The below example is merging three ApiResponses as one if every three ApiResponses are successful.

 

 

ApiResponseMergePolicy

ApiResponseMergePolicy is a policy for merging response data depend on the success or not.

  • IGNORE_FAILURE: Regardless of the merging order, ignores failure responses in the responses.
  • PREFERRED_FAILURE (default): Regardless of the merging order, prefers failure responses in the responses.
  •  

toLiveData

We can get a LiveData that contains success data if the response is an ApiResponse.Success. If our goal is only to get a LiveData that holds success data, we can emit the onSuccess extension.

 

 

If we want to transform the original data and get a LiveData that contains transformed data using success data if the response is an ApiResponse.Success.

 

 

toFlow

We can get a Flow that emits success data if the response is an ApiResponse.Success and the data is not null.

 

 

If we want to transform the original data and get a flow that contains transformed data using success data if the response is an ApiResponse.Success and the data is not null.

 

 

Conclusion

Designing and constructing the network response handling is important because it affects many factors in our project. If we failed to well-design the network structure, not only our business codes could not be constructed clearly but also UI logic. In this post, I’ve introduced the library Sandwich that constructs a standardized callback interface of the response from the network callback communication. By using this library, we can reduce our construction time on the initial project and we can handle the callback responses fastly depending on their state. And you can check out some use case repositories of this library in the below list. Thanks for reading and happy coding!

 

Ues cases

  • Pokedex — 🗡️ Android Pokedex using Hilt, Motion, Coroutines, Flow, Jetpack (Room, ViewModel, LiveData) based on MVVM architecture.
  • DisneyMotions — 🦁 A Disney app using transformation motions based on MVVM (ViewModel, Coroutines, LiveData, Room, Repository, Koin) architecture.
  • MarvelHeroes — ❤️ A sample Marvel heroes application based on MVVM (ViewModel, Coroutines, LiveData, Room, Repository, Koin) architecture.
  • TheMovies2 — 🎬 A demo project using The Movie DB based on Kotlin MVVM architecture and material design & animations.

 

Sandwich

skydoves/Sandwich

🥪 A lightweight and standardized Android network response interface for handling successful data and error responses…

github.com

 

 

 

Tags: Android, Retrofit, Okhttp, Http, Network

 

View original article at: 


 

Originally published: January 22, 2021

Android News
Our Engineering Roadmap
Our Engineering Roadmap

By Mark Ng

We just completed our engineering road map for our Android apps at Australia Post. Each year we get together and try to decide on what we are going to do from an engineering perspective for the next 12 months. Each team gets to decide on what should be done now, what they want to complete by the end of the year and whats on the horizon for next year.

By ProAndroidDev -
Android News
Android Activity Lifecycle considered harmful
Android Activity Lifecycle considered harmful

By Eric Silverberg

The Android activity lifecycle is one of the first architectural concepts learned by a new Android developer. Ask any Android dev and they’ll likely all have seen this handy diagram from Google: 

By ProAndroidDev -
Android News
Our Safe Approach to Android Jetpack Navigation in a Multi-Modular App
Our Safe Approach to Android Jetpack Navigation in a Multi-Modular App

By Alejandro Weichandt

It has been a year since we started working on the Android version of the mobile app at Sync. During that year, we faced more than once that moment when we had to choose which path to follow on an Architectural decision. This story is about Navigation.

By ProAndroidDev -
Android News
Custom KotlinX Serializers
Custom KotlinX Serializers

By Jobin Lawrance

Let’s say we have a third-party class that we are using as a type in one of our data class that we want to be serialized, then we have to write a custom serializable for @Serializable to work.

 

By ProAndroidDev -
droidcon News

Tech Showcases,

Developer Resources &

Partners

/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/home-details/EmployerBrandingHeader
EmployerBrandingHeader
https://jobs.droidcon.com/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/jobs-droidcon/jobs.droidcon.com
jobs.droidcon.com

Latest Android Jobs

http://www.kotlinweekly.net/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/kotlin-weekly/Kotlin Weekly
Kotlin Weekly

Your weekly dose of Kotlin

https://proandroiddev.com/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/pad/ProAndroidDev
ProAndroidDev

Android Tech Blogs, Case Studies and Step-by-Step Coding

/detail?content-id=/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Zalando/Zalando
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Zalando/Zalando
Zalando

Meet one of Berlin's top employers

/detail?content-id=/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Academy for App Success/Academy for App Success
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Academy for App Success/Academy for App Success
Academy for App Success

Google Play resources tailored for the global droidcon community

Follow us

Team droidcon

Get in touch with us

Write us an Email

 

 

Quicklinks

> Code of Conduct

> Terms and Conditions

> How to hold a conference

> FAQs

> Imprint

Droidcon is a registered trademark of Mobile Seasons GmbH Copyright © 2020. All rights reserved.

powered by Breakpoint One