I have a requirement to use the query parameter that is passed inside retrofit query inside onResponse if it is successful. I can't use global variable as it will change before getting the response.
The onResponse method gives you the original call related to that response:
call!!.request()
the request contains the url related to that particular response, the headers and, if present, the body.
If you parse those data you can get the original parameters
call.request().url().queryParameter("id") this solved the problem
Related
I am calling an external API (on which I do not have a control to make any change) using Spring's RestTemplate. The API returns response with an array as response body if the results are found and if not it returns response with String as response body stating "No records found". I am getting an exception when I am getting the no company found message because I typecasted the RestTemplate call to the custom object
ResponseEntity<Student[]> studentDetails = restTemplate.getForEntity(studentUrl, Student[].class);
The above code throws exception when the API returns String message "No records found".
What is the best way to deal with such a scenario?
In that case, you probably may use it like that
ResponseEntity<Object> studentDetails = restTemplate.getForEntity(studentUrl, Object.class);
And then check for the response type and cast the result.
I am defining the Call objects in a Retrofit2 interface, to consume an external Rest API.
For most of the calls, we have something similar to :
#POST("/api/v1/methodEndPoint")
public Call<MethodResponse> methodName(#Body MethodRequest methodRequest);
However, my question is: How should I define a method if there is no Response object (a POST call, with no response body, we just mind about the status). Retrofit throws an exception if I just write the following:
#POST("/api/v1/methodEndPoint")
public Call methodName(#Body MethodRequest methodRequest);
Thanks for your help, have a nice day!
For defining a method without any response in Retrofit 2, the return type of method should be Void
You can try like :
#POST("/api/v1/methodEndPoint")
Call <Void> methodName(#Body MethodRequest methodRequest);
Use ResponseBody. Basically, you can do it like this:
#POST("/api/v1/methodEndPoint")
public Call<ResponseBody> methodName(#Body MethodRequest methodRequest);
You will have access to onResponse and onFailure callbacks however there will be no data deserialisation attempt
The premise:
We use session tokens that expire after 3 hours
I have to use a special call called auth
Currently, when a session token expires, we do not preemptively refresh it, but instead attempt the call and if that call returns 401-UNAUTHORIZED we call auth and retry the call. It works, but it isn't pretty
We're using Retrofit1 and RxJava1 (updating is currently not an option)
I would like to change it up in such a way, where I would check whether I need to refresh the token BEFORE I make the call.
I want to achieve that by chaining Observables and sharing the Auth-Observable between calls
Think like this:
Check if the SessionToken is about to expire or already expired
Start Auth-Call (returns an Observable)
Chain my call into the Auth-Call Observable
when another call happens and sees that the sessiontoken is close to expiring, check if there is an ongoing Auth-Call. If there is, chain the new call into Auth-Call
1st question: Is this actually a smart idea?
2nd question: Is this actually possible?
3rd question: How the hell do I do this?
The trick to this was using a Singleton Observable
Observable<AuthResponse> mAuthSingleton = retrofit.authenticate()
.doOnNext( response -> saveSessionToken(response.getSessionToken())
.share();
Observable<AuthResponse> getAuthCallWhenNecessary(){
if(sessionToken == null ||sessionToken.isAboutToExpire())
return mAuthSingleton;
else
return Observable.just(new AuthResponse());
}
Observable<WhateverResponse> getWhatever(){
return getAuthCallWhenNecessary().flatMap(response -> retrofit.getWhatever());
}
your calls don't care whether the AuthResponse, they get when calling getAuthCallWhenNecessary, is a real one, they only care that they get a response-object from Auth
Here's my (kinda) documented work-sample: https://gist.github.com/TormundsMember/ebcb3782b14477a3d5b72e898929fe61
I think you can use the combinaison of repeatWhen operator and delay operator.
After the delay of token expiration , re-subscribe to your observable to get the new token.
Hope this helps.
Sorry for my english.
What I did in my case might be a bit overkill but it works - I wrapped all Retrofit interfaces with my own proxy class:
Create your own proxy of your Retrofit interface with Proxy.newProxyInstance
The proxy creates the Retrofit implementation with Retrofit.Builder()
In the proxy's public Object invoke(Object proxy, Method method, Object[] args) call the actual Retrofit implementation, before this call you can check if the token was valid or not, if not, refresh the token and call the Retrofit method implementation in switchMap()
If the retrofit call fails because of 401, you can use resultObservable.retryWhen(errorCheck) to check for this error, refresh the access token and call the Retrofit method implementation again.
(I also stored the result in a BehaviorSubject and returned this subject whenever a part of my app requested for the result (by calling an interface method), and I only refreshed the result from network when a separate refresh() call was issued)
I have the following code:
#RequestMapping(value="/mobile/device", method = RequestMethod.PUT)
public ResponseEntity<Void> flagDevice (#RequestBody List<MobileDeviceData> devicedataList, #RequestHeader(value="special_code") String specialCode) {
// Implementation details
}
Each instance of MobileDeviceData that gets created needs to have a param field filled in with the RequestHeader special_code.
How would I go about doing this so that it is fully populated by the time the flagDevice method body gets called?
Thanks in advance.
This is non trivial.
An HttpMessageConverter is already provided that deserializes the JSON, that's the MappingJackson2HttpMessageConverter. It has access to request headers. You could extend that class to also use the headers for deserialization (this is extremely difficult to do generically, as opposed to only for MobileDeviceData).
You could use Spring AOP, intercept the method, retrieve the arguments, cast to the appropriate types, and assign the value yourself.
The solution I would go for is the simplest: do it yourself in the handler method. Loop the the List and use a corresponding setter to set the specialCode for each MobileDeviceData.
Another option is to define your own HandlerMethodArgumentResolver specifically for List<MobileDeviceData> parameters that need to be constructed from header vales.
I am new to extjs and am trying to implement the update operation. I tried to Google but could not find a solution.
I have form which is used for updating records in a store. For this, I am using the following code in the controller,
var formPanel = Ext.getCmp('displayForm');
var record = formPanel.getRecord();
var values = formPanel.getValues();
record.set(values);
companyStore.sync();
The record.set() method calls the method(i.e.rest service) pointed by the URL specified for update operation in the store’s proxy.
How can I read the values passed by the record.set() method in the rest service coded in java.
I tried with,
#POST
#Produces({"application/xml"})
#Path("/updateData")
public CompanyDataService updateData(#QueryParam("company") Company companyObj){
//code
}
but companyObj is unable to capture the parameter values
There is no "values" parameter being passed. Based on the configuration of your store proxy's Writer (http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.data.writer.Json), the parameters will either be a single root value (if encode configuration is true), or as individually named parameters, one per model field being persisted.
How is your Writer configured?
Also, just to clarify, record.set() doesn't trigger the proxy call unless autoSync is configured to true. In you example, I suspect the proxy call is happening because you explicitly call sync().