I receive (Step 1) a soapString from a server and I would like to forward (Step 2) this String to another server.
public interface StepTwoRestAdapter {
#Headers({"Content-Type:text/xml"})
#POST("/services/step2/forwardSoap")
Observable<String> order(#Body SoapString soapString);
}
In this case above, the afgter my.server.com which is "/webservices/step2/forwardSoap" is constant always. How can I make this part variable?
The trick here is, that the second server (for step 2) is specified in the response of the first reponse.
EDIT:
Now, I use the proposal from #Tabish Hussain
public interface StepTwoRestAdapter {
#Headers({"Content-Type:text/xml"})
#POST("/{urlPath}")
Observable<String> order(#Body SoapString soapString, #Path("urlPath") String urlPath);
}
and then I call
restAdapter.create(StepTwoRestAdapter.class).order(new TypedString(soapString), uriPath)
whereas my uriPath is "services/step2/forwardSoap"
But retrofit then calls:
https://my.server.com/services%2Fstep2%2FforwardSoap
As you can see '/' was replaces by "%2F"
Do it like this
public interface StepTwoRestAdapter {
#Headers({"Content-Type:text/xml"})
#POST("/services/{soapString}/forwardSoap")
Observable<String> order(#Path("soapString") SoapString soapString);
}
Check this links, you should be able to find answer there:
https://futurestud.io/tutorials/retrofit-2-how-to-use-dynamic-urls-for-requests
https://futurestud.io/tutorials/retrofit-2-how-to-change-api-base-url-at-runtime-2
I think the easiest way is:
public interface StepTwoRestAdapter {
#Headers({"Content-Type:text/xml"})
#POST
Observable<String> order(#Url String url, #Body SoapString soapString);
}
If you are using Retrofit 1 check this one:
https://medium.com/#kevintcoughlin/dynamic-endpoints-with-retrofit-a1f4229f4a8d#.7atwl0o3t
Related
public interface ASarTaLineApi {
#FormUrlEncoded
#POST("GetWarDee.php")
Observable<GetWardeeResponse> getWardee(#Field("access_token") String access_token);
#FormUrlEncoded
#POST("GetMealShop.php")
Observable<GetMealShopResponse> getMealShop(#Field("access_token") String access_token);}
How to call parallel with flatMap in RxJava.I want two Object at the same time.Please answer me details and I don't understand kotlin.Thanks.
You can use zipWith for a parallel operation like this:
String token = "hello";
api.getMealShop(token)
.zipWith(api.getWardee(token), new BiFunction<GetMealShopResponse, GetWardeeResponse, Pair<GetMealShopResponse, GetWardeeResponse>>() {
#Override
public Pair<GetMealShopResponse, GetWardeeResponse> apply(GetMealShopResponse getMealShopResponse, GetWardeeResponse getWardeeResponse) throws Exception {
return new Pair<>(getMealShopResponse, getWardeeResponse);
}
});
Or lambda'd:
api.getMealShop(token)
.zipWith(api.getWardee(token), Pair::new);
You get back an Observable<Pair<GetMealShopResponse, GetWardeeResponse>>. If that's what not you want, just put something else in the zipper parameter.
So the scenario is one where we need to make 2 retrofit calls,
#GET("/")
Observable<Search> searchMovies(#Query("apikey") String apiKey, #Query("s") String searchKey);
#GET("/")
Observable<Details> getMovie(#Query("apikey") String apiKey, #Query("t") String searchKey);
the first one is to get a list and then for each item in that list we will make a new call in order to get further information about that movie.
So the first question I have is how can I chain these 2 calls together inside ond rxjava method ?
The second question that i have follows up from this one in that I want to chain these 2 calls together inside and Rxjava method but then return a new observable pojo object based upon a few fields from each of the response. So for example say that request 1 contains "Name" and then request 2 contains "plot". I want to compose what would be a list of MovieInformation pojo objects based on these 2 fields and wrap that into an observable.
You should use flatMap operator to chain these two calls.
Normally getMovie() should take in parameteres the result of searchMovies(). I suppose that apiKey,searchKey are the result of getMovies(apikey,searchKey) :
yourretrofitservice.searchMovies(apikey,searchKey)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
//waiting for response of yourretrofitservice.searchMovies()
.flatMap(new Func1<Search, Observable<Details>>() {
#Override
public Observable<Details> call(Search search_result) {
return yourretrofitservice.searchMovies(apiKey, searchKey); //maybe searchKey = search_result (you should define how to set the result of the First Retrofit call in the second call
}
})
//waiting for the response of yourretrofitservice.getMovie()
.flatMap(new Func1<Search, Observable<YourPojoClass>>() {
#Override
public Observable<YourPojoClass> call(Search search_result) {
//do something with pojo_object
return pojo_object; second call
}
})
.subscribe(new Action1<YourPojoClass>() {
#Override
public void call(YourPojoClass pojo_object) {
//Your final action
}
});
FlatMap operator : http://reactivex.io/documentation/operators/flatmap.html
I want know if I can use Retrofit with this type of url:
https://example.com/mobile_api.php?action=test
if I try to use Retrofit with a Base Url without the slash at the end of the url I get an Exception, my url is this:
https://example.com/mobile_api.php
not this:
https://example.com/mobile_api.php/
How I can do?
Maybe this can help.
Retrofit 1
#GET("/path/to/api/mobile_api.php")
void getAction(#Query("action") String action, Callback<YourCallBack> response);
Retrofit 2
#GET("/path/to/api/mobile_api.php")
Call<YourCallBack> getAction(#Query("action") String action);
Make an interface something like this
#GET("mobile_api.php")
void doSomeAction(#Query('action')String action, Callback<YourResponseClass> callback);
and then call this with your Restclient instance.
I was wondering about token authentication with Retrofit/RxJava.
I was refactoring my code to use a DataManager, such that the activity evokes a method in the presenter, the presenter subscribes to the datamanager.getTrips which is then responsible for the call to the api.
I want to make sure that my accesstoken is valid, and if it is not generate it first and then complete the task. Would doOnCompleted be a good way of achieving this or is there a better way?
/*In DataManager, service is the REST Interface*/
public Observable<VtTripResponseModel> getTrips(final String start, final String end, final String time, final String date){
if(accessToken.isValid()){
return service.getTrip(accessToken.getAccessString(),start,end,time,date,JSON_PARAM);
}
else{
generateAccessToken().doOnCompleted(new Action0() {
#Override
public void call() {
getTrips(start, end, time, date);
}
});
}
/*What do I return here? Since this will not be reached*/
}
To elaborate on #david.mihola 's answear you could do it like this:
Observable.just(accessToken.isValid())
.flatMap(valid -> {
if(valid){
return Observable.just(accessToken);
} else {
return generateAccessToken();
})
.flatMap(token -> service.getTrip(token.getAccessString(),start,end,time,date,JSON_PARAM))
So that the first flatMap generates token if it is not valid and if it is, then simply passes it on(this assumes that generateToken() returns Observable<AccessToken>). Second flatMap is just the thing that you wanted to do.
And to give some context to #MatBos's elaboration on my comment, especially with regard to your question
What do I return here? Since this will not be reached
It felt quite eye-opening for me when I realized that an Observable (or at least a cold-one, like the one we are talking about here, and the one that #MatBos described in his answer) is essentially a description of a future computation.
Returning an Observable just means that you return a blue-print for what should happen if and when someone (i. e. the code that called your getTrips method) actually subscribes to that Observable. Of course, an Observable is also an asynchronous stream of events, but I think that my description here is valid, too.
So, what do you return? A description that says:
If someone subscribes
1. First check if we have valid access token
2. a) If we do, just forward the access token for later use
b) If we don't, generate a new one access token and forward that
3. Take whatever access token you get - it is now guaranteed to be valid and use to retrieve the trips.
4. Forward them to the subscriber when they are ready.
And that description is exactly the Observable that #MatBos described.
Thank you for the input, In the meantime I was flying away and found a similar, but formulated in another way post: Retrofit with RxJava which had an answer in it.
My code now looks like:
/*In DataManager*/
public Observable<VtTripResponseModel> getTrips(String start, String end, String time, String date){
return service.getTrip(accessToken.getAccessString(),start,end,time,date,JSON_PARAM);
}
public Observable<VtResponseModel> getLocationByInput(String input){
return service.getLocationByInput(accessToken.getAccessString(),input,JSON_PARAM);
}
/*SF 26201420*/
public <T> Func1<Throwable,? extends Observable<? extends T>> refreshTokenAndRetry(final Observable<T> toBeResumed) {
return new Func1<Throwable, Observable<? extends T>>() {
#Override
public Observable<? extends T> call(Throwable throwable) {
// Here check if the error thrown really is a 401
if (isHttp401(throwable)) {
return service.getAccessToken(CREDENTIALS, DEVICE).flatMap(new Func1<AccessToken, Observable<? extends T>>() {
#Override
public Observable<? extends T> call(AccessToken token) {
accessToken = token;
return toBeResumed;
}
});
}
// re-throw this error because it's not recoverable from here
return Observable.error(throwable);
}
};
}
And the method in my presenter now looks like
public void loadRepositories(String search){
subscription = manager.getLocationByInput(search)
.onErrorResumeNext(manager.refreshTokenAndRetry(Observable.defer(() -> manager.getLocationByInput(search))))
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(application.defaultSubscribeScheduler())
.subscribe(new Subscriber<VtResponseModel>() {... etc}
Now when the first call is made after starting the application, it will generate an accesstoken since I recieve a 401. Then that accesstoken is stored within the manager, and reused until there is a new 401 (after it has expired).
I'm using Retrofit/OkHttp in a project and recently I've discovered RxJava. Combining it with Retrofit seems easy and straightforward but with regular async callbacks in Retrofit in success(...) we are receiving the parsed POJO and the Response. This is quite useful and in some of my callbacks I'm using both of these objects. I can't seem to find a way to do this with RxJava.
Is it possible to obtain the parsed POJO and the Response object at the same time?
The way RxJava works is that the onNext method always emits exactly one value, so you won't be able to get something like (as it would break the contract):
onNext(T value, Response respone);
The closest could be an Observable<ResponseAndPojo<T>> where ResponseAndPojo is as follows:
public class ResponseAndPojo<T> {
private final T value;
private final Response response;
public ResponseAndPojo(T value, Response response) {
this.value = value;
this.response = response;
}
// add getters here
}
Such an Observable would then emit items with:
onNext(ResponseAndPojo<T> responseAndPojo)
and you would have access to both the Response and the POJO.
Now, how to construct such an Observable:
One way would be to create some kind of Subject (maybe a BehaviorSubject, but for single requests it does not really matter) and then in the Retrofit success method put the return values into the Subject.
So, in some kind of RetrofitWrapper class of your own you would have
public Observable<ResponseAndPojo<YourPojoClass>> getResponseAndPojoObservable() {
final BehaviorSubject<ResponseAndPojo<YourPojoClass>> retrofitSubject = BehaviorSubject.<ResponesAndPojo<YourPojoClass>>create();
yourRetrofitService.getSomething(new Callback<YourPojoClass>() {
#Override
public void success(YourPojoClass pojo, Response response) {
retrofitSubject.onNext(new ResponseAndPojo(pojo, response);
retrofitSubject.onCompleted();
}
});
return retrofitSubject;
}
As you can see, from the outside the Subject looks like an Observable<ResponseAndPojo<YourPojoClass>>, which is exactly what we wanted.