I'm pretty new to RxJava and Retrofit and am trying to write my API calls with it. All the API calls return a JSON body on error which is in the general format as,
{"errors":[{"code":100, "message":"Login/Password not valid", "arguments":null}]}
Currently my code for the login API call (others are also similar) is,
mConnect.login(id, password)
.subscribe(new Subscriber<Token>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted()");
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError(): " + e);
if (e instanceof HttpException) {
// dump e.response().errorBody()
}
}
@Override
public void onNext(Token token) {
Log.d(TAG, "onNext(): " + token);
}
});
When I get an error at the onError(), I would like to automatically decode the JSON in the error body to a POJO instead and use that. Is there a way to do this preferably in one place for all other API calls. Any help is appreciated.
you can simply use "response. message(). toString()" which will give the same error string in a more readable format.
Rx gives you a very granular control over which threads will be used to perform work in various points within a stream. To point the contrast here already, basic call approach used in Retrofit is only scheduling work on its worker threads and forwarding the result back into the calling thread.
RxAndroid is an extension of RxJava and it contains the Android threads to be used in the Android Environment. To use RxJava in retrofit environment we need to do just two major changes: Add the RxJava in Retrofit Builder. Use Observable type in the interface instead of Call.
I would suggest the use of a reusable Transformer along with the onErrorResumeNext operator to encapsulate your logic. It'd look something like this:
<T> Observable.Transformer<T, T> parseHttpErrors() {
return new Observable.Transformer<T, T>() {
@Override
public Observable<T> call(Observable<T> observable) {
return observable.onErrorResumeNext(new Func1<Throwable, Observable<? extends T>>() {
@Override
public Observable<? extends T> call(Throwable throwable) {
if (throwable instanceof HttpException) {
HttpErrorPojo errorPojo = // deserialize throwable.response().errorBody();
// Here you have two options, one is report this pojo back as error (onError() will be called),
return Observable.error(errorPojo); // in this case HttpErrorPojo would need to inherit from Throwable
// or report this pojo back as part of onNext()
return Observable.just(errorPojo); //in this case HttpErrorPojo would need to inherit from <T>
}
// if not the kind we're interested in, then just report the same error to onError()
return Observable.error(throwable);
}
});
}
};
}
Pay attention to the comments in the code, since you have to make the decision whether you want to report the parsed response onError() or onNext().
Then you can use this transformer anywhere in your API calls like this:
mConnect.login(id, password)
.compose(this.<Token>parseHttpErrors()) // <-- HERE
.subscribe(new Subscriber<Token>() {
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted()");
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError(): " + e);
if (e instanceof HttpErrorPojo) {
// this will be called if errorPojo was reported via Observable.error()
}
}
@Override
public void onNext(Token token) {
Log.d(TAG, "onNext(): " + token);
if (token instanceof HttpErrorPojo) {
// this will be called if errorPojo was reported via Observable.just()
}
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With