SlideShare uma empresa Scribd logo
1 de 24
Baixar para ler offline
Extending Retrofit for fun
and profit
Matt Clarke - 4 July 2017, Orion Health Akl
Retrofit (v2.1.0) recap
// Retrofit turns your HTTP API into a Java (or Kotlin)
interface
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Define a light-weight interface that matches the REST endpoint you want to talk to
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service =
retrofit.create(GitHubService.class);
Now you can use a Retrofit instance to generate a working version of your interface
to make requests with
Call<List<Repo>> repos = service.listRepos("octocat");
// synchronous/blocking request
Response<List<Repo>> response = repos.execute();
// do stuff with response...
To actually make a request, you just call the method you defined in your interface.
You’ll get back a Call object.
You can use this to make a sync request like this...
Call<List<Repo>> repos = service.listRepos("octocat");
// asynchronous request
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call,
Response<List<Repo>> response) {
// do stuff with response...
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
// uh oh!
}
});
Or you can use Call objects to make an asynchronous requests by calling enqueue
and passing a callback
Call<List<Repo>> repos = service.listRepos("octocat");
// asynchronous request
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call,
Response<List<Repo>> response) {
// do stuff with response...
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
// uh oh!
}
});
You might notice there are some similarities here with a library we’re all familiar with.
This Callback object looks a lot like an RxJava Observer or Subscriber.
Wouldn’t it be cool if the service returned an Observable instead of a Call? Then we
could go nuts with operators, subscribing on a different thread, etc.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addCallAdapterFactory(
RxJavaCallAdapterFactory.create()
)
.build();
GitHubService service = retrofit.create(GitHubService.class);
// Retrofit turns your HTTP API into a Java (or Kotlin)
interface
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
// Retrofit turns your HTTP API into a Java (or Kotlin)
interface
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
Q: How does this magic work?
A: Call Adapters
WTF is a Call Adapter?
● Knows how to convert Call<R> to some other
type T
● E.g. the RxJavaCallAdapter can convert a
Call<Repo> into Observable<Repo>
WTF is a Call Adapter?
public interface CallAdapter<R, T> {
T adapt(Call<R> call);
Type responseType();
}
WTF is a Call Adapter?
● You also need to create a
CallAdapter.Factory to give to the
Retrofit.Builder
● Factories are given the chance to create
CallAdapters for a given return type in the
Service interface (e.g. Observable)
abstract class Factory {
/**
* Returns a call adapter for interface methods that
* return returnType, or null if it cannot be handled by
* this factory.
*/
public abstract @Nullable CallAdapter<?, ?> get(Type returnType,
Annotation[] annotations,
Retrofit retrofit);
// ..
}
Concrete example - Engage Mobile
Problem: Network Error handling
● The RxJavaCallAdapter just forwards low-level network
Exceptions via onError()
Problem: Network Error handling
val repoObservable = service.listRepos("octocat")
repoObservable.subscribe(object : Observer<List<Repo>> {
override fun onNext(repos: List<Repo>) {
// show repos in UI...
}
override fun onCompleted() {}
override fun onError(e: Throwable) {
when (e) {
is SocketTimeoutException -> showTimeoutError()
is ConnectException -> showNoConnectionToServerError()
is UnknownHostException -> showNoNetworkConnectionError()
is HttpException -> makeSenseOfHttpResponseCode(e)
}
}
})
You need to handle all of the
possible network errors
somewhere in order to do the
right thing in the UI.
Don’t want to have a copy of this
`when` statement everywhere
there’s a network call.
Also, these errors are low-level
and depend on the HTTP client
you’re using: if you change
HTTP libraries you don’t want all
of your UI code to break - they’re
separate concerns.
Network Error Handling
sealed class NetworkError(cause: Throwable?) :
Throwable(cause) {
class NetworkUnreachableError(cause: Throwable? = null) :
NetworkError(cause)
class ServerUnreachableError(cause: Throwable? = null) :
NetworkError(cause)
class GenericNetworkError(cause: Throwable? = null) :
NetworkError(cause)
} Solution: abstract away low-level HTTP client errors by defining your own
higher-level network error types
Network Error Handling
fun map(input: Throwable): Throwable {
if (!networkAccessAvailable())
return NetworkError.NetworkUnreachableError(input)
return when (input) {
is SocketTimeoutException ->
NetworkError.ServerUnreachableError(cause = input)
is ConnectException ->
NetworkError.ServerUnreachableError(cause = input)
is UnknownHostException ->
NetworkError.NetworkUnreachableError(cause = input)
is HttpException ->
mapHttpException(input)
else -> input
}
}
...Then you can extract out a common network error mapper,
and apply this to the reactive stream with the
onErrorResumeNext operator
Network Error Handling
repoObservable
.onErrorResumeNext { e ->
Observable.error(mapNetworkError(e))
}
.subscribe(object : Observer<List<Repo>> {
// ..
})
The problem with this is you still need to remember to apply this
mapper to all reactive streams that contain a network request.
Having to remember = a red flag. Better to structure the system
such that it does the right thing by default (remembers for you)
Live code demo

Mais conteúdo relacionado

Mais procurados

Request dispatching in servlet
Request dispatching in servletRequest dispatching in servlet
Request dispatching in servlet
vikram singh
 
Servlet api &amp; servlet http package
Servlet api &amp; servlet http packageServlet api &amp; servlet http package
Servlet api &amp; servlet http package
renukarenuka9
 

Mais procurados (20)

HTTP Whiteboard - OSGI Compendium 6.0 - How web apps should have been! - R Auge
HTTP Whiteboard - OSGI Compendium 6.0 - How web apps should have been! - R AugeHTTP Whiteboard - OSGI Compendium 6.0 - How web apps should have been! - R Auge
HTTP Whiteboard - OSGI Compendium 6.0 - How web apps should have been! - R Auge
 
Whats New in the Http Service Specification - Felix Meschberger
Whats New in the Http Service Specification - Felix MeschbergerWhats New in the Http Service Specification - Felix Meschberger
Whats New in the Http Service Specification - Felix Meschberger
 
Servlet life cycle
Servlet life cycleServlet life cycle
Servlet life cycle
 
MongoDB World 2016: Implementing Async Networking in MongoDB 3.2
MongoDB World 2016: Implementing Async Networking in MongoDB 3.2MongoDB World 2016: Implementing Async Networking in MongoDB 3.2
MongoDB World 2016: Implementing Async Networking in MongoDB 3.2
 
Request dispatching in servlet
Request dispatching in servletRequest dispatching in servlet
Request dispatching in servlet
 
Why async matters
Why async mattersWhy async matters
Why async matters
 
Kotlin 1.2: Sharing code between platforms
Kotlin 1.2: Sharing code between platformsKotlin 1.2: Sharing code between platforms
Kotlin 1.2: Sharing code between platforms
 
Wrapping java in awesomeness aka condensator
Wrapping java in awesomeness aka condensatorWrapping java in awesomeness aka condensator
Wrapping java in awesomeness aka condensator
 
Servlet and servlet life cycle
Servlet and servlet life cycleServlet and servlet life cycle
Servlet and servlet life cycle
 
SERVIET
SERVIETSERVIET
SERVIET
 
Flask & Flask-restx
Flask & Flask-restxFlask & Flask-restx
Flask & Flask-restx
 
Background Jobs with Resque
Background Jobs with ResqueBackground Jobs with Resque
Background Jobs with Resque
 
Contract-driven development with OpenAPI 3 and Vert.x | DevNation Tech Talk
Contract-driven development with OpenAPI 3 and Vert.x | DevNation Tech TalkContract-driven development with OpenAPI 3 and Vert.x | DevNation Tech Talk
Contract-driven development with OpenAPI 3 and Vert.x | DevNation Tech Talk
 
Servlet lifecycle
Servlet lifecycleServlet lifecycle
Servlet lifecycle
 
Php resque
Php resquePhp resque
Php resque
 
Rack
RackRack
Rack
 
Servlet api &amp; servlet http package
Servlet api &amp; servlet http packageServlet api &amp; servlet http package
Servlet api &amp; servlet http package
 
Generating cross platform .NET based azure IoTdevice
Generating cross platform .NET based azure IoTdeviceGenerating cross platform .NET based azure IoTdevice
Generating cross platform .NET based azure IoTdevice
 
Asynchronous handlers in asp.net
Asynchronous handlers in asp.netAsynchronous handlers in asp.net
Asynchronous handlers in asp.net
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle Build
 

Semelhante a Extending Retrofit for fun and profit

Semelhante a Extending Retrofit for fun and profit (20)

Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
 
Arquitecturas de microservicios - Medianet Software
Arquitecturas de microservicios   -  Medianet SoftwareArquitecturas de microservicios   -  Medianet Software
Arquitecturas de microservicios - Medianet Software
 
1 java servlets and jsp
1   java servlets and jsp1   java servlets and jsp
1 java servlets and jsp
 
Java servlets
Java servletsJava servlets
Java servlets
 
Retrofit library for android
Retrofit library for androidRetrofit library for android
Retrofit library for android
 
Retrofit Library In Android
Retrofit Library In AndroidRetrofit Library In Android
Retrofit Library In Android
 
Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networking
 
Native REST Web Services with Oracle 11g
Native REST Web Services with Oracle 11gNative REST Web Services with Oracle 11g
Native REST Web Services with Oracle 11g
 
RESTEasy
RESTEasyRESTEasy
RESTEasy
 
Clojure and the Web
Clojure and the WebClojure and the Web
Clojure and the Web
 
May 2010 - RestEasy
May 2010 - RestEasyMay 2010 - RestEasy
May 2010 - RestEasy
 
Introduction to Retrofit
Introduction to RetrofitIntroduction to Retrofit
Introduction to Retrofit
 
Servlet
Servlet Servlet
Servlet
 
Web Server and how we can design app in C#
Web Server and how we can design app  in C#Web Server and how we can design app  in C#
Web Server and how we can design app in C#
 
Implement Service Broker with Spring Boot #cf_tokyo
Implement Service Broker with Spring Boot #cf_tokyoImplement Service Broker with Spring Boot #cf_tokyo
Implement Service Broker with Spring Boot #cf_tokyo
 
Ruby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVCRuby on Rails vs ASP.NET MVC
Ruby on Rails vs ASP.NET MVC
 
Servlet 01
Servlet 01Servlet 01
Servlet 01
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
 
Networked APIs with swift
Networked APIs with swiftNetworked APIs with swift
Networked APIs with swift
 
Java Web Programming [2/9] : Servlet Basic
Java Web Programming [2/9] : Servlet BasicJava Web Programming [2/9] : Servlet Basic
Java Web Programming [2/9] : Servlet Basic
 

Último

%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 

Último (20)

WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 

Extending Retrofit for fun and profit

  • 1. Extending Retrofit for fun and profit Matt Clarke - 4 July 2017, Orion Health Akl
  • 3. // Retrofit turns your HTTP API into a Java (or Kotlin) interface public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); } Define a light-weight interface that matches the REST endpoint you want to talk to
  • 4. Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build(); GitHubService service = retrofit.create(GitHubService.class); Now you can use a Retrofit instance to generate a working version of your interface to make requests with
  • 5. Call<List<Repo>> repos = service.listRepos("octocat"); // synchronous/blocking request Response<List<Repo>> response = repos.execute(); // do stuff with response... To actually make a request, you just call the method you defined in your interface. You’ll get back a Call object. You can use this to make a sync request like this...
  • 6. Call<List<Repo>> repos = service.listRepos("octocat"); // asynchronous request repos.enqueue(new Callback<List<Repo>>() { @Override public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) { // do stuff with response... } @Override public void onFailure(Call<List<Repo>> call, Throwable t) { // uh oh! } }); Or you can use Call objects to make an asynchronous requests by calling enqueue and passing a callback
  • 7. Call<List<Repo>> repos = service.listRepos("octocat"); // asynchronous request repos.enqueue(new Callback<List<Repo>>() { @Override public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) { // do stuff with response... } @Override public void onFailure(Call<List<Repo>> call, Throwable t) { // uh oh! } }); You might notice there are some similarities here with a library we’re all familiar with. This Callback object looks a lot like an RxJava Observer or Subscriber. Wouldn’t it be cool if the service returned an Observable instead of a Call? Then we could go nuts with operators, subscribing on a different thread, etc.
  • 8. Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build(); GitHubService service = retrofit.create(GitHubService.class);
  • 9. Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .addCallAdapterFactory( RxJavaCallAdapterFactory.create() ) .build(); GitHubService service = retrofit.create(GitHubService.class);
  • 10. // Retrofit turns your HTTP API into a Java (or Kotlin) interface public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); }
  • 11. // Retrofit turns your HTTP API into a Java (or Kotlin) interface public interface GitHubService { @GET("users/{user}/repos") Observable<List<Repo>> listRepos(@Path("user") String user); }
  • 12. Q: How does this magic work?
  • 14. WTF is a Call Adapter? ● Knows how to convert Call<R> to some other type T ● E.g. the RxJavaCallAdapter can convert a Call<Repo> into Observable<Repo>
  • 15. WTF is a Call Adapter? public interface CallAdapter<R, T> { T adapt(Call<R> call); Type responseType(); }
  • 16. WTF is a Call Adapter? ● You also need to create a CallAdapter.Factory to give to the Retrofit.Builder ● Factories are given the chance to create CallAdapters for a given return type in the Service interface (e.g. Observable)
  • 17. abstract class Factory { /** * Returns a call adapter for interface methods that * return returnType, or null if it cannot be handled by * this factory. */ public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit); // .. }
  • 18. Concrete example - Engage Mobile
  • 19. Problem: Network Error handling ● The RxJavaCallAdapter just forwards low-level network Exceptions via onError()
  • 20. Problem: Network Error handling val repoObservable = service.listRepos("octocat") repoObservable.subscribe(object : Observer<List<Repo>> { override fun onNext(repos: List<Repo>) { // show repos in UI... } override fun onCompleted() {} override fun onError(e: Throwable) { when (e) { is SocketTimeoutException -> showTimeoutError() is ConnectException -> showNoConnectionToServerError() is UnknownHostException -> showNoNetworkConnectionError() is HttpException -> makeSenseOfHttpResponseCode(e) } } }) You need to handle all of the possible network errors somewhere in order to do the right thing in the UI. Don’t want to have a copy of this `when` statement everywhere there’s a network call. Also, these errors are low-level and depend on the HTTP client you’re using: if you change HTTP libraries you don’t want all of your UI code to break - they’re separate concerns.
  • 21. Network Error Handling sealed class NetworkError(cause: Throwable?) : Throwable(cause) { class NetworkUnreachableError(cause: Throwable? = null) : NetworkError(cause) class ServerUnreachableError(cause: Throwable? = null) : NetworkError(cause) class GenericNetworkError(cause: Throwable? = null) : NetworkError(cause) } Solution: abstract away low-level HTTP client errors by defining your own higher-level network error types
  • 22. Network Error Handling fun map(input: Throwable): Throwable { if (!networkAccessAvailable()) return NetworkError.NetworkUnreachableError(input) return when (input) { is SocketTimeoutException -> NetworkError.ServerUnreachableError(cause = input) is ConnectException -> NetworkError.ServerUnreachableError(cause = input) is UnknownHostException -> NetworkError.NetworkUnreachableError(cause = input) is HttpException -> mapHttpException(input) else -> input } } ...Then you can extract out a common network error mapper, and apply this to the reactive stream with the onErrorResumeNext operator
  • 23. Network Error Handling repoObservable .onErrorResumeNext { e -> Observable.error(mapNetworkError(e)) } .subscribe(object : Observer<List<Repo>> { // .. }) The problem with this is you still need to remember to apply this mapper to all reactive streams that contain a network request. Having to remember = a red flag. Better to structure the system such that it does the right thing by default (remembers for you)