Chain Retrofit calls for authorization and subsequent calls using RxJava - android

I am a new with Rxjava. I want to capture access token (received as part of headers) from the response of the first api call and then use that access token (as header) for subsequent api calls.
Note: the in the first api call, the response has no body,only headers are returned.
My Network Interface:
public interface NetworkInterface {
#POST("https://appauth.treuspan/Login")
Observable<Response<Void>> getAuthDetails(
#Header("Content-Type") String contentType,
#Body AuthRequestDetails authRequestDetails
);
#POST("https://appauth.treuspan//storedetails")
Observable<StoreDetailsResponse> getStoreDetails(
#Header("Content-Type") String contentType,
#Header("Accept") String accept,
#Header("Authorization") String authorization,
#Body AuthRequestBody authRequestBody
);
}
My observable methods:
public Observable<Response<Void>> getAuthObservable() {
return NetworkClient.getRetrofit().create(NetworkInterface.class)
.getAuthDetails("application/x-www-form-urlencoded",
new AuthRequestDetails().getAuthRequestDetails())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Response<Void>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Response<Void> voidResponse) {
String access_token_received = voidResponse.headers().get("access_token");
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
The above doesn't compile. Its compile says:
Incompatible type:
required: io.reactivex.Observable<retrofit2.Response<java.lang.Void>>
Found: void
If I am able to successfully make the above call then i have to use the access token as part of header in the subsequent call as follows
public Observable<StoreDetailsResponse> getStoreDetailsObservable() {
return NetworkClient.getRetrofit().create(NetworkInterface.class)
.getStoreDetails("application/x-www-form-urlencoded",
"application/json",
"Bearer access_token_received",
new AuthRequestBody().getAuthRequestBody())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<StoreDetailsResponse>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(StoreDetailsResponse response) {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
}
The above code also doesn't compile. It says:
Incompatible type:
required: io.reactivex.Observable<com.example.androidtest.model.StoreDetailsResponse>
Found: void
Please suggest how can i achieve this.

subscribe(...) will return a Subscription
Try to edit your code, make method return a Subscription like this
public Subscription getAuthObservable() {
return NetworkClient.getRetrofit().create(NetworkInterface.class)
.getAuthDetails("application/x-www-form-urlencoded",
new AuthRequestDetails().getAuthRequestDetails())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Response<Void>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(Response<Void> voidResponse) {
String access_token_received = voidResponse.headers().get("access_token");
}
});
}

Related

onComplete is not getting called when returning response as Flowable

I am trying to make webservie call using retrofit and rxjava 2. i was exploring two different approach to use RxJava2. problem is i am getting response whene i use Observable but it is not working with Flowable. Logs are not getting printed when using Flowable i tried to debug it but its not going inside onNext or onComplete or onError. only onSubscribe gets executed.
1) using observable as return type
new WebRequestManager().getContactObservable(userRequest)
.subscribe(new Observer<ResponseData>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(ResponseData responseData) {
Log.e(TAG , "data "+responseData.getStatus());
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
Log.e(TAG , "data complete");
}
}
);
2) Using flowable as return type
new WebRequestManager().getContactFlowable(userRequest)
.subscribe(new Subscriber<ResponseData>() {
#Override
public void onSubscribe(Subscription s) {
Log.e(TAG , "contact subscription ");
}
#Override
public void onNext(ResponseData responses) {
Log.e(TAG , "contact onNext ");
}
#Override
public void onError(Throwable t) {
}
#Override
public void onComplete() {
Log.e(TAG , "contact onComplete ");
}
});
Rest contact retrofit api
public interface ContactApi {
#POST(WebRequest.GET_CONTACTS)
Flowable<ResponseData> getContactFlowable(#Body UserRequest userRequest);
#POST(WebRequest.GET_CONTACTS)
Observable<ResponseData> getContactObservable(#Body UserRequest userRequest);
}
call to webservice
public Flowable<ResponseData> getContactsData(UserRequest userRequest){
return webRequest.getWebClient().create(ContactApi.class).getContacts(userRequest);
}
public Observable<ResponseData> getContact(UserRequest userRequest){
return webRequest.getWebClient().create(ContactApi.class).getContact(userRequest);
}
getting retrofit instance
public static Retrofit getWebClient(){
//if(okHttpClient == null)
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(120,TimeUnit.SECONDS)
.readTimeout(120,TimeUnit.SECONDS)
.writeTimeout(120,TimeUnit.SECONDS)
.addInterceptor(new WebRequestInterceptor("\"application/json\""))
.build();
// if(client == null)
client = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(LoganSquareConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return client;
}
With Subscribers, you have to call request to get items:
new WebRequestManager().getContactFlowable(userRequest)
.subscribe(new Subscriber<ResponseData>() {
#Override
public void onSubscribe(Subscription s) {
Log.e(TAG , "contact subscription ");
s.request(Long.MAX_VALUE); // <---------------------------------
}
#Override
public void onNext(ResponseData responses) {
Log.e(TAG , "contact onNext ");
}
#Override
public void onError(Throwable t) {
}
#Override
public void onComplete() {
Log.e(TAG , "contact onComplete ");
}
});
See also DisposableSubscriber with its example.

Retry API request when network connected with RxRetrofit?

Is there anyway to retry a retrofit http request when network connection available with Rx-java?
This is my request method
public DisposableObserver<List<Photo>> getNewPhotos(final int page,
int perPage,
String orderBy,
ObservableTransformer<List<Photo>, List<Photo>> observableTransformer,
final Callback<List<Photo>> callBack) {
return photoService.getPhotos(page, perPage, orderBy)
.compose(observableTransformer)
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
#Override
public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
return null;
}
})
.onErrorResumeNext(new Function<Throwable, ObservableSource<? extends List<Photo>>>() {
#Override
public ObservableSource<? extends List<Photo>> apply(Throwable throwable) throws Exception {
return Observable.error(throwable);
}
})
.subscribeWith(new DisposableObserver<List<Photo>>() {
#Override
public void onNext(List<Photo> value) {
callBack.onSuccess(value);
}
#Override
public void onError(Throwable e) {
callBack.onError(new NetworkError(e));
}
#Override
public void onComplete() {
}
});
}
i think maybe i could do something in retryWhen() method.
i want retrofit to trigger for internet connection and retry the last request when the connection is back.
i know the traditional way to retry but i think there must be a method or something in Rx-java to handle this.
if someone knows its good to share it with me.

SocketException unsubscribing request without onError

I'm trying to make a request using RxJava and Retrofit(2.3). I'm expecting that in case of any error I can retry or show a message to the client.
However, I notice that sometimes I have a SocketException which results in not calling onError, apparently the subscriber of the request just unsubscribes without calling anything else (not onComplete neither onError). Anyone knows why this is happening and how can I solve this in a generic way (without simply doing onUnsubscribe() and checking if the observable did not send any onError or onComplete)?
On my interface I have something like this:
#GET("userInfo")
Observable<List<UserInfo>> getUserInfo(#Header("token") String token);
This is how I create my observable:
public Observable<UserModel> requestUserInfo(final String token) {
return mService.getUserInfo(token)
.retryWhen(new RetryWithDelay(HTTP_RETRIES), HTTP_TIME_BETWEEN_RETRIES)))
.flatMap(new Func1<List<UserInfo>, Observable<UserModel>() {
#Override
public Observable<UserModel> call(List<UserInfo> userInfo) {
return Observable.just(new UserModel(userInfo));
}
});
}
------ UPDATE -------
This is how I call the requestUserInfo method on my presenter
private CompositeSubscription mCompositeSubscription = null;
public PresenterX(ViewX view) {
...
mCompositeSubscription = new CompositeSubscription();
}
public void getUserModel() {
String userToken = new AccessModel().getUserToken();
mCompositeSubscription.add(mNetworkRequestModel.requestUserInfo(userToken)
.flatMap(new Func1<UserModel, Observable<UserModel>>() {
#Override
public Observable<UserModel> call(UserModel userModel) {
if (userModel != null) {
saveUserModel(userModel); //sync saving
return Observable.just(userModel);
} else {
return Observable.error(new SaveException());
}
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<UserModel>() {
#Override
public void onCompleted() {
Log.i(TAG, "Subscriber was completed")
}
#Override
public void onError(Throwable e) {
Log.i(TAG, "Subscriber called onError")
mView.handleErrors(e);
}
#Override
public void onNext(UserModel userModel) {
Log.i(TAG, "Subscriber called onNext")
mView.populateUserInfo(userModel);
}
}));
}
//called by activity when onDestroyMethod is called
//I assume this is not called as I have other requests running parallelly to this getUserModel() and they are not terminated, despite having other compositeSubscription to manage those
public void onDestroy(){
mCompositeSubscription.clear();
}
As I have a HttpLoggingInterceptor, this is the only log printed to me while the request suddenly stops.
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
#Override
public void log(String message) {
LOG.info(Thread.currentThread(), String.format("%s", message));
}
});
Here is the log exception:
I/ExampleApp-ApiClient(21338): : Thread: 1343 | <-- HTTP FAILED: java.net.SocketException: Socket closed
Because you try to get rx object (Observable) from server. You have incorrect function
Remove Observable
#GET("userInfo")
List<UserInfo> getUserInfo(#Header("token") String token);

How to do unit testing for retrofit2 callbacks?

I want to do an unit test that verifies if function1() or function2() were called. I haven't work with callbacks before, can you give me any idea about how to do it?
public void sendData(HttpService service, Document userData) {
Call<String> call = service.updateDocument(getId(), userData);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
function1(response.code());
}
#Override
public void onFailure(Call<String> call, Throwable t) {
function2();
}
});
}
I couldn't try, but it should work. Maybe you have to fix generic type
casting errors like mock(Call.class);.
#Test
public void should_test_on_response(){
Call<String> onResponseCall = mock(Call.class);
doAnswer(invocation -> {
Response response = null;
invocation.getArgumentAt(0, Callback.class).onResponse(onResponseCall, response);
return null;
}).when(onResponseCall).enqueue(any(Callback.class));
sendData(....);
// verify function1
}
#Test
public void should_test_on_failure(){
Call<String> onResponseCall = mock(Call.class);
doAnswer(invocation -> {
Exception ex = new RuntimeException();
invocation.getArgumentAt(0, Callback.class).onFailure(onResponseCall, ex);
return null;
}).when(onResponseCall).enqueue(any(Callback.class));
sendData(....);
// verify function2
}

Retrofit2 POST request with Body

I need make POST request with parameters "guid=1" in Body. i use Retrofit2
I try :
#POST("/api/1/model")
Call<ApiModelJson> getPostClub(#Body User body);
User Class:
public class User {
#SerializedName("guid")
String guid;
public User(String guid ) {
this.guid = guid;
}
MailActivity:
User user =new User ("1");
Call<ApiModelJson> call = service.getPostClub(user);
call.enqueue(new Callback<ApiModelJson>() {
#Override
public void onResponse(Response<ApiModelJson> response) {
}
#Override
public void onFailure(Throwable t) {
dialog.dismiss();
}
How make this request?
you have to call call.enqueue, providing an instance of Callback< ApiModelJson>, where you will get the response. enqueue executes your backend call asynchronously. You can read more about call.enqueue here
With code below, you can make the request synchronously:
ApiModelJson responseBody = call.execute();
If you want it to be asynchronous:
call.enqueue(new Callback<ApiModelJson>() {
#Override
public void onResponse(Response<ApiModelJson> response, Retrofit retrofit) {
}
#Override
public void onFailure(Throwable t) {
}
});

Categories

Resources