I've a cloud function that uses "context.auth.uid" and for JSON parsing reasons I want to trigger it by using Retrofit instead of Firebase functions API. But I'm getting this error when I try so: Request has incorrect Content-Type. app/google-services.json. And I don't know how to pass the Authentication information that function API passes.
So here are my codes:
Cloud Functions HTTP Function:
exports.getMatches = functions.https.onCall((req, context) => {
var uid = context.auth.uid;
console.log("uid: ", uid);
});
Android SearchAPI Interface for Retrofit
public interface ElasticSearchAPI
{
#POST("getMatches/")
Call<ElasticHitsObject> getMatches(#Header("Content-Type") String
content_type,#Header("Authorization") String secretKey);
}
Android calling the function
Call<ElasticHitsObject> call = searchAPI.getMatches("app/google-services.json","api_key");
Retrofit doesn't know how to invoke callable functions, as you have declared in your code. They have a special protocol that's designed to be used with Firebase client SDK.
If you want to use an HTTP client library to invoke a Cloud Functions, you should make an HTTP function instead, not a callable. Note that they are declared differently. One starts with functions.https.onCall() and the other with functions.https.onRequest().
Related
I have a retrofit api interface where one of the calls requires OAuth1 authentication and the others do not. I am trying to find a way to add the Authentication header without using an Interceptor for a few reasons.
At the time the OkHttp Client is created I wont know OAuth1 keys and the client is used for other things too.
It is only one request that needs OAuth1 authentication
What I was trying to do is wrap the interface call in a Call and then adding the header before I process
val call = api.getRecentTweetsV1("$query -filter:replies -filter:retweets")
val oauth = Oauth1Signing.Builder()
.consumerKey(consumerKey)
.consumerSecret(consumerSecret)
.accessToken(token)
.accessSecret(tokenSecret).build()
val authHeader = oauth.signRequest(call.request())
call.request().headers.newBuilder().add("Authorization", authHeader).build()
val headers = call.request().headers
response = call.execute().body()
The problem is I don't see the header getting added in, the call.request().headers value is always empty after I try to add it in.
I cant use the #Header parameter in the interface call because the OAuth1Signer (modified version of this, I removed the Interceptor usage) takes in a OkHttp Request object to build the header.
Is there another way to add the header after the request has been built?
I have two APIs say API 1 and API 2. API 1 get authentication token and API 2 get user profile info. I need to hit API 2 from ViewModel but if API 2 gives an authentication error, then I need to get new token first and then hit API 2(user info)
Currently, I use RxJava Single and Retrofit for all APIs but for APIs one by one. There are a lot of APIs that use authentication token and if it expires in any of the APIs then I need to call authentication API and get the token again and then call the APIs with a new authentication token.
What should be the best way to design a wrapper so that it can be used with all APIs with code reusability as well.
Thanks in advance.
I have some idea. If you have basemodel for getting response for API, you can make custom getter for response code and check if response code in token_expired.
This is sample response that I got From API.
{
response_code: "200",
response_msg: "",
result: ...
}
And this is my BaseModel.
class BaseModel<T> {
#SerializedName("response_code")
var response_code: Int? = null
get() {
if(field == ErrorStatusCode.TOKEN_EXPIRE) {
ErrorCodeHandler.requestNewToken()
}
return field
},
#SerializedName("response_msg")
var response_msg: String? = null
#SerializedName("result")
var data: T? = null
}
So whenever token expire, I will request Net token by call ErrorCodeHandler.requestNewToken()
But If you want to recall API that found token timeout I have no idea what to do too.
PS. Hope this help.
This day is the first time for me to use dotNet web API for my project.
This is the code of my controller
public IEnumerable<Waybill> Get(string id_wb) {
List<Waybill> lstWaybill = new List<Waybill>();
lstWaybill = objway.GetWaybill(id_wb).ToList();
return lstWaybill;
}
That API can work well if I'm call using this link :
http://localhost:56127/api/waybill/?id_wb=00000093
but I don't know how to call that link from my android app (I'm using retrofit)
#GET("Waybill/{id_wb}/id_wb")
Call<Waybill> getWaybillData(#Path("id_wb") String id_wb);
There are 3 options.
First one is to use Retrofit's #Query annotation.
#GET("Waybill/")
Call<Waybill> getWaybillData(#Query("id_wb") String id_wb);
The second one is to #Path annotation
#GET("Waybill/?id_wb={id_wb}") // notice the difference in your code and my code
Call<Waybill> getWaybillData(#Path("id_wb") String id_wb);
The third option is to use #Url annotation. With this option, you need to prepare fully qualified URL before calling/using getWaybillData() method in your activity or fragment. Keep in mind that #Url method overrides base URL set in Retrofit client.
#GET // notice the difference in your code and my code
Call<Waybill> getWaybillData(#Url String completeUrl);
If you follow 3rd option you need to prepare full URL in your activity like below.
String url = "http://<server_ip_address>:56127/api/waybill/?id_wb=00000093";
YourInterface api = ...
Call<Waybill> call = api.getWaybillData(url);
call.enqueue({/* implementation */});
I see a difference in the sample URL you mentioned and usage in Retrofit API interface.
In sample URL waybill is small and in API interface it is Waybill. Please ensure that you're using the right URL.
I've been following this blog entry which shows how to mock requests with Mockito and Retrofit. The problem is I'm using both along Robospice, which it doesn't require to provide a Callback as parameter on the service interface (as it would be a synchronous call):
#GET("/foo/bar")
User foo(#Query("bar") String baz);
So I cannot intercept the callback on my tests on this way:
Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture());
User user = new User();
cb.getValue().success(user, null);
Is any way to achieve this?. Thanks!
Mock the service interface and then script it to return the value you desire.
doReturn(new User()).when(service).foo(anyString());
You can later verify that this method was called.
verify(service).foo(anyString())
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);