Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJava2/Retrofit2 - Handling null for 204 PUT and DELETE requests

So, I am working with an API that is clearly defined and is designed to not return a payload body on DELETE and PUT operations.

This was acceptable in Rx 0.X and Rx 1.x. Now I'm updating to Rx 2 and having an existential crisis with how I should handle the null values. The content-length and body are of course null causing:

java.lang.NullPointerException: Null is not a valid element
   at io.reactivex.internal.queue.SpscLinkedArrayQueue.offer(SpscLinkedArrayQueue.java:68)
   at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.onNext(ObservableObserveOn.java:116)
   at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:63)

in the doOnNext.

I've seen many people suggest Optional<> but I need to support Java7 as well for use case reasons. I attempted back-porting but I couldn't quite get it to work. I also don't want to bloat and import the Guava library for their version.

I also noticed flatMap may also help me handle this opposed to map and I'm reading up on the differences.

Currently I have a very crude, OkHttp3 Interceptor that will check the status, check if the payload is empty, and add dummy content which just feels so wrong.

I've also tried to add a convert factory.

Can anyone offer suggestions and guide me on what the proper path is? Sure, the API can change, but 204 isn't supposed to have a payload by virtue of it's definition as an HTTP status code.

Relevant Dependencies

compile('com.squareup.retrofit2:retrofit:2.1.0') {
     exclude module: 'okhttp'
} 
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
compile 'com.squareup.okhttp3:okhttp:3.5.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.5.0'

compile 'io.reactivex.rxjava2:rxjava:2.0.5'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'com.trello.rxlifecycle2:rxlifecycle:2.0.1'
compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.0.1'
like image 962
isuPatches Avatar asked Jan 28 '17 19:01

isuPatches


1 Answers

You need to declare your request method in Retrofit like:

@DELETE(...)
Call<Void> deleteFile(...args);

In RxJava your Observable has to be typed:

@DELETE(...)
Observable<Response<Void>> deleteFile(...args);

In onNext() or doOnNext() you will receive the Response normally, if the request is successful.

Having Void will not send the response body to the converter for further deserialization. All empty-response Calls should be typed as Void.

like image 124
Nikola Despotoski Avatar answered Sep 20 '22 06:09

Nikola Despotoski