Android Annotations: Query params gets appended to url? - android

#Get("/ServiceTest?version=1&dateRange={dateRange}")
ResponseModel getDateRangeTest(String dateRange);
in RestClient interface this make the following Get
http://localhost:8080/ServiceTest/2014-01-29%25202014-01-29?version=1" resulted in 400 (Bad Request); invoking error handler
Am i doing something wrong in sending the query params.
I want address this way:
/ServiceTest?version=1&dataRange=2014-01-29%25202014-01-29
Which in this case somehow i am failed to generate with Android annotations #Get
Answer: My calls were not correct and main problem was with uri encode, correct one is
/ServiceTest?version=1&dataRange=2014-01-29%202014-01-29

you might do wrong.
Your server get /ServiceTest
but you access server with address /ServiceTest/2014-01-29%25202014-01-29
Look careful that your server receive as /ServiceTest?version=1&dateRange={dateRange}
and {dataRange} is what you intend to give as variable.
Your address should be /ServiceTest?version=1&dataRange=2014-01-29%25202014-01-29
== EDIT ==
I'm not familiar with Android Get annotation, but try this.
#Get("/ServiceTest?version=1&dateStart={dateStart}&dateEnd={dateEnd}")
ResponseModel getDateRangeTest(String dateStart, String dateEnd);
and access with /ServiceTest?version=1&dataStart=2014-01-29&dateEnd=2014-01-29
Note that I change argument for more specific. and it would be a better approach.

Related

Firestore Timestamp is (seconds: 0, nanoseconds: 0) when using Retrofit

I have the problem related to parsing Firestore Timestamp in Android app.
Summary
In my Firebase Firestore, I have a collection of comments. Every comment looks like this
(time is of type Timestamp)
I've built REST API using Cloud Functions. There is a GET method for comments endpoint. Sharing the whole code doesn't have sense, the important fact is, the response from that endpoint looks like this
As you can see, the response looks good, everything's okay.
The problem
Now, I have the Android app using Retrofit to communicate with the API. It makes a request to aforementioned endpoint and gets the response (response is a <List<CommentResponse>>).
import com.google.firebase.Timestamp
data class CommentResponse(
val placeId: String,
val userUid: String,
val userDisplayName: String,
val userPhotoUrl: String,
val time: Timestamp,
val text: String
)
But when I do Log.d(response.body), I get (I cut the unimportant data)
[CommentResponse(placeId=opactwo, userUid=e09E...82, userDisplayName=Bartek Pacia, userPhotoUrl=https: .../photo.jpg, time=Timestamp(seconds=0, nanoseconds=0), text=This place is very beautiful :D)]
Timestamp vanished. It's not null, but it points to the beggining of the Epoch (1.1.1970). It's just 0 sec, 0 nanosec. I don't use any custom converters or whatever, just the "beginner level Retrofit".
And, well, that's it.
I've no idea why the Timestamp changes to 0,0.
I'd be very grateful if somebody could help me.
Thank you in advance.
You're assuming that Retrofit knows how to deserialize the timestamp based on its default JSON serialization from the server. It doesn't know how to do that. You're going to have to manage that yourself.
When your function serializes the timestamp, it's using the default serialization of the contents of the document. It's looking at the Timestamp object and saying "hey, there's an object, so in order to serialize that, I'm just going to copy all of its properties into the output". If you look at the source for Timestamp, you'll see that it's using properties _seconds and _nanoseconds to hold the components of the Timestamp. So, that explains the JSON output you see.
On the Java (or Kotlin) client side, all that is effectively going to be just a Map object, and the type information is gone (and it wouldn't be helpful as JavaScript stuff doesn't simply map to Java stuff). No one knows that it was a Timestamp type object that came across the wire. All it knows is that there's an object with _seconds and _nanoseconds.
What you need to do is put some smarts into your code (maybe as a hint to Retrofit in the form of a custom converter) to help it recognize what's in that time JSON object, and convert that to a Timestamp object locally using the java Timestamp constructor.
Or, if you don't mind losing a few nanoseconds of precision, just have the function convert the Timestamp into a the time in milliseconds, send that over the wire, and have the client simply convert that to a java Date object.
You might also want to stop depending on the internal details of the JavaScript Timestamp object. Since _seconds and _nanoseconds are effectively private details, you are depending on something that might change in the future. Consider instead explicitly serializing the Timestamp in your function using the data from its public methods getSeconds() and getNanoseconds().

RxJava and-then-when

I am trying to use RxJava in combination with Retrofit in my Android app.
I came to a point where I need to retrieve (GET) a url from some model class, and if its not available, POST to another endpoint to generate it, then retrieve it with GET again.
The idea is that the end result is always a url (provided there was not an error, of course), so if its not there, we create it and then retrieve it.
I can do this with RxJava by just nesting calls, but this does not seem to "reactive", so I thought maybe the and-when-then sounds like what im looking for? I tried looking for examples but these three words are quite difficult to search due to them being so common.
Is it possible to combine observables to achieve what I describe?
Let's assume you have the following methods:
apiManager.makeGETRequest(); //returns Url or throws an Exception
apiManager.makePOSTRequest(); //returns Url
Use handy onErrorResumeNext operator:
apiManager.makeGETRequest()
.onErrorResumeNext(t -> apiManager.makePOSTRequest())
...
It intercepts an Exception and replaces it with Observable. In your case if makeGETRequest() succeeds, than downstream will ignore onErrorResumeNext, otherwise apiManager.makePOSTRequest() will be called.
P.S. Don't forget to check what kind of exception you receive in onErrorResumeNext.
I hope this can be useful for you.
https://github.com/darylteo/rxjava-promises/tree/master/rxjava-promises
If you need code sample for retrofit + rx usage you can follow this link.
http://randomdotnext.com/retrofit-rxjava/

Retrofit Query Annotation Without Ampersand

I am trying to make an API call to a mobile backend with Retrofit 2.0. In my API call, i have to make necessary call to this URL
https://api.backendless.com/v1/data/Users?where=followings.objectId=%270B3BA7F9-260F-B378-FF9A-3C2448B8A700%27
To form this URL in Retrofit i have been using below interface
#GET("Users?where=")
Call<List<User>> getFollowers(#Query("followings.objectId") String objectId);
This interface call puts an ampersand before the query parameters and generates a URL like below
https://api.backendless.com/v1/data/Users?where=&followings.objectId=%270B3BA7F9-260F-B378-FF9A-3C2448B8A700%27
I tried to overcome this with Path annotation but i keep getting "URL query string must not have replace block. For dynamic query parameters using #Query" error.
API that i am trying to connect requires a "where=" clause for filtering by design. I have no permission to change that. What i want is somehow tell Retrofit not to put an ampersand sign before the query parameter or any workarounds for this issue.
Any help is appreciated.
For those who seek for similar answers, I came up with below solution
I declared my interface with #Url
#GET
Call<List<User>> getFollowers(#Url String objectId);
and generated related URL part as an extension method
public String toFollowerRequest(){
return RestGlobals.BASE_URL + "Users?where=followings.objectId=%27" + objectId + "%27";
}
#GET("{path}")
Call> getFollowers(#Path("path") path, #Query("followings.objectId") String objectId);
getFollowers("Users?where=", ...)

Where in Retrofit build the full JSON before sending it?

I am using retrofit an get Bad Request , I would want to know if there is a place in this library where builds the full JSON in string format before sending it.
If it's about inspecting the JSON at runtime for debugging purposes, you can call setLogLevel(LogLevel.FULL) on your RestAdapter.Builder.
FULL logs the headers, body and metadata for both requests and responses to logcat.
new String(((TypedByteArray) request.getBody()).getBytes());
In order to build a JSON formatted body, create an object with a class whose properties are the same that you want to send to the server. The GSON Library set up (or whichever library you are using) with the RestAdapter should send the request with the body in JSON format.
Also ensure that the call is #POST annotated and the parameter annotd with #Body Below is an example:
#POST("/login")
User login(#Body LoginUser loginUser);

POST request with Android Annotation REST Service

I am using Android Annotation in my project and trying to send POST request through following code, however there is something wrong in following code as I am not getting response as expected:
#Rest(rootUrl = "http://xyz.com", converters = {GsonHttpMessageConverter.class})
public interface A {
#Post("/authenticate/email/")
public Object attemptLogin(Map data);
}
Where data is (key, value) pair. Is there anything I am missing perhaps Do I have to set request-header or data should not be JSON?
I found the solution from Rest client using Android-Annotations.
Like the GET requests, it is extremely simple to send POST requests using Android-Annotations. One difference is that you need to define the parameters that you are going to send as a custom class (e.g. Event class in the example below) or if you want to control this dynamically, then a Map (e.g. a MultiValueMap). The url for the request can still be constructed in a similar fashion using the variables enclosed inside {...} and the response can be handled similarly as in GET requests.
#Post("/events")
void addEvent(Event event);
#Post("/events/{id}")
void addEventById(Event event, long id);
#Post("/authenticate/event/")
Object authenticateEventData(MultiValueMap data);

Categories

Resources