Not getting any data from Retrofit. Its sending empty request to server - java

I have a problem with Retrofit call. I had call to post data on server, call is giving me back 200 response that means call is successful, but it's not saving any data to database and returning message "request is empty" in server stacktrace. Getting no data in response.
Interface call
#Headers({"org-id: vuk"})
#POST("/dmp/user/loginwithotp")
Call<ResponseAPI> signInWithOTP(#Body RequestBody jsonObject);
Retrofit Call
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT))
.addInterceptor(loggingInterceptor)
.addNetworkInterceptor(new CacheInterceptor(mContext))
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl )
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.client(client)
.build();
return retrofit;
}
public static VuAPIServices geVuAPIServices() {
VuAPIServices vuAPIServices = getRetrofit().create(VuAPIServices.class);
return vuAPIServices;
}
Code for send call request and response call in activity
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("mobileNumber", mobileNumber);
RequestBody body = RequestBody.create(json.toString(), MediaType.parse("application/json;charset=UTF-8"));
Call<ResponseAPI> responseAPICall = ApiClient.geVuAPIServices().signInWithOTP(body);
responseAPICall.enqueue(new Callback<ResponseAPI>() {
#Override
public void onResponse(Call<ResponseAPI> call, retrofit2.Response<ResponseAPI> response) {
if(!response.isSuccessful()) {
Log.e("TAG", "response: "+new Gson().toJson(response.body()) );
}
}
#Override
public void onFailure(Call<ResponseAPI> call, Throwable t) {
Log.e("TAG", "onFailure: "+t.toString() );
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
Response POJO
#SerializedName("flag")
private int flag;
#SerializedName("message")
private String message;
#SerializedName("status")
private Boolean status;
#SerializedName("otp")
private String otp;
#SerializedName("locked")
private Boolean locked;
#SerializedName("firstTimeLogin")
private Boolean firstTimeLogin;
#SerializedName("firstLogin")
private Boolean firstLogin;
Getter and Setters...
Postman Image
What should I change in my code? I welcome every hint. The status i m getting is 200 but with empty request on server side.
Updated with Response Result
E/TAG: response: {"firstLogin":false,"firstTimeLogin":false,"flag":0,"fromInternalApp":false,"locked":false,"mobileNumber":"4455332266","noToken":false,"status":false}

It could be because you are sending a json object. You can try making a request object instead and send that:
public class RequestObject {
private String mobileNumber;
public RequestObject(String mobileNumber) {
this.mobileNumber = mobileNumber;
}
public String getMobileNumber() {
return mobileNumber;
}
public setMobileNumber(String mobileNumber) {
this.mobileNumber = mobileNumber;
}
}
And then send it in the request:
#Headers({"org-id: vuk"})
#POST("/dmp/user/loginwithotp")
Call<ResponseAPI> signInWithOTP(#Body RequestObject requestObject); // here

I have solved my problem it was a problem that i needed to send a host in header of okhttp interceptor
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.addHeader("Content-Type", "application/json")
.addHeader("User-Agent", System.getProperty("http.agent"))
.addHeader("Host", "localhost:8080")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
Soon after i added this in interceptor the problem solved and it got the response returned successfully.
E/TAG: response: {"firstLogin":false,"firstTimeLogin":false,"flag":1,"fromInternalApp":false,"locked":false,"message":"true OTP sent successfully on mobile number for Initial Login","noToken":false,"otp":"573287","status":false}
Thanks #rya for your valuable efforts with you tried to help me.

Related

OkHttpClient authenticator without retrofit

Im trying to refresh an Access token in my application following this solution.
My actual problem is handling the callback and then return the new request in the authenticate method.
I tried using an interface to return a String from my callback method but then I cant assign it to a variable, nor can I return the new request from there since its inside my onResponseListener.
How can I solve this issue?
public Request authenticate(Route route, Response response) throws IOException {
// GetAuthRequest is a void method, and I cant assign a String value on the callback.
getAuthRequest(new AuthResponse() {
#Override
public Request onSuccess(String token) {
return response.request().newBuilder()
.header("Authorization", "Bearer " + token)
.build();
}
});
I was using an Asynchronous call instead of Synchronous. Ended up making a method that returns an String like so:
private String getAuthRequest() {
// Make the request above
try (Response response = httpClient.newCall(request).execute()) {
JSONObject jsonObject = new JSONObject(response.body().string());
return jsonObject.getString("access_token");
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return null;
}

What I make wrong in my htttp Post Java in Android using Retrofit2?

I am trying to do a http Post using retrofit2,
I have the the Technical specifications
I have an error accepted in the Technical specifications
And I make the http Post how below. But I always get
Response{protocol=http/1.1, code=422, message=Unprocessable Entity, url=https://XXX/api/v1/token/}.
Can someone help me?
API Interface:
public interface PostService {
#Headers({
"Content-type: application/json"
})
#POST("api/v1/token/")
Call<String> sendPosts(#Body Posts posts);
}
My Class for the request(POJO):
public class Posts {
#SerializedName("username")
private String username;
#SerializedName("password")
private String password;
#SerializedName("grant_type")
private String grant_type;
#SerializedName("scope")
private String scope;
#SerializedName("client_id")
private String client_id;
#SerializedName("client_secret")
private String client_secret;
public Posts() {
username = "test";
password = "test";
}
}
My Retrofit Post request in my Activity:
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://xxxxxx/")
.client(okHttpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
postsService = retrofit.create(PostService.class); //l'oggetto retrofit deve rispettare ciò che è scritto nell'interfaccia creata PostService
Posts post = new Posts();
Call<String> call = postsService.sendPosts(post);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
System.out.println("TEST!!!!!!!!!!!!" + response.toString()); //Response here
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.toString(), Toast.LENGTH_LONG).show();
}
});
I solved the the problem.
As #Fabio Piunti says I have To send a x-www-form-urlencoded,
So I Modified the code as below:
public interface PostService {
#Headers({
"Content-Type: application/x-www-form-urlencoded"
})
#FormUrlEncoded //I have added this as well
#POST("api/v1/token/")
Call<Posts> sendPosts( #Field("username") String title, #Field("password") String password);
}
My request in the Activity now is:
....
Call<Posts> call = postsService.sendPosts("test", "test");
//eseguo la mia chiamata (Call) post
call.enqueue(new Callback<Posts>() {
#Override
public void onResponse(Call<Posts> call, Response<Posts> response) {
System.out.println("TEST!!!!!!!!!!!!" + response.toString());
}
#Override
public void onFailure(Call<Posts> call, Throwable t) {
System.out.println("TEST Error!!!!!!!!!!!!" + t.toString());
}
});

Refresh Access Token Retrofit2 + RXJava2

This approach always worked when updating a token. That is, with each request if I received an error 401, the operator retryWhen() triggered it updated the token.
Here is the code:
private Observable<TokenModel> refreshAccessToken() {
Map<String, String> requestBody = new HashMap<>();
requestBody.put(Constants.EMAIL_KEY, Constants.API_EMAIL);
requestBody.put(Constants.PASSWORD_KEY, Constants.API_PASSWORD);
return RetrofitHelper.getApiService().getAccessToken(requestBody)
.subscribeOn(Schedulers.io())
.doOnNext((AccessToken refreshedToken) -> {
PreferencesHelper.putAccessToken(mContext, refreshedToken);
});
}
public Function<Observable<Throwable>, ObservableSource<?>> isUnauthorized (){
return throwableObservable -> throwableObservable.flatMap((Function<Throwable, ObservableSource<?>>) (Throwable throwable) -> {
if (throwable instanceof HttpException) {
HttpException httpException = (HttpException) throwable;
if (httpException.code() == 401) {
return refreshAccessToken();
}
}
return Observable.error(throwable);
});
}
I call isUnauthorized() at the retryWhen() operator where I make a request to the server
class RetrofitHelper {
static ApiService getApiService() {
return initApi();
}
private static OkHttpClient createOkHttpClient() {
final OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(chain -> {
Request originalRequest = chain.request();
AccessToken accessToken= PreferencesHelper.getAccessToken(BaseApplication.getInstance());
String accessTokenStr = accessToken.getAccessToken();
Request.Builder builder =
originalRequest.newBuilder().header("Authorization", "Bearer " + accessTokenStr);
Request newRequest = builder.build();
return chain.proceed(newRequest);
});
return httpClient.build();
}
private static ApiService initApi(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants._api_url)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(createOkHttpClient())
.build();
return retrofit.create(ApiService.class);
}
}
But we recently added Basic Auth, and now at the first request I get 401 and retryWhen() tries to update the Token, but still gets 401. That is, the doOnNext() does not work, but immediately the onError() works
private static Observable<AccessToken> refreshAccessToken() {
return RetrofitHelper.getApiService()
.getAccessToken(
Credentials.basic(
Constants._API_USERNAME, Constants._API_PASSWORD
),
Constants._API_BODY_USERNAME,
Constants._API_BODY_PASSWORD,
Constants._API_BODY_GRANT_TYPE
)
.doOnNext((AccessToken refreshedToken) -> {
PreferencesHelper.putObject(BaseApplication.getInstance(), PreferenceKey.ACCESS_TOKEN_KEY, refreshedToken);
}
});
}
// Api Service
public interface ApiService {
// Get Bearer Token
#FormUrlEncoded
#POST("oauth/token")
Observable<AccessToken> getAccessToken(#Header("Authorization") String basicAuth,
#Field("username") String username,
#Field("password") String password,
#Field("grant_type") String grantType);
}
Here, tell me why this is a mistake? Why at the first request I get 401, and from the second request everything works?
I want to suggest a better solution.
public class RefreshTokenTransformer<T extends Response<?>> implements ObservableTransformer<T, T> {
private class HttpCode {
private static final int UNAUTHORIZED_HTTP_CODE = 401;
}
private ApiService mApiService;
private UserRepository mUserRepository;
public RefreshTokenTransformer(ApiService service, UserRepository userRepository) {
mApiService = service;
mUserRepository = userRepository;
}
#Override
public ObservableSource<T> apply(final Observable<T> stream) {
return stream.flatMap(new Function<T, ObservableSource<T>>() {
#Override
public ObservableSource<T> apply(T response) throws Exception {
if (response.code() == HttpCode.UNAUTHORIZED_HTTP_CODE) {
return mApiService.refreshToken(mUserRepository.getRefreshTokenHeaders())
.filter(new UnauthorizedPredicate<>(mUserRepository))
.flatMap(new Function<Response<TokenInfo>, ObservableSource<T>>() {
#Override
public ObservableSource<T> apply(Response<TokenInfo> tokenResponse) throws Exception {
return stream.filter(new UnauthorizedPredicate<T>(mUserRepository));
}
});
}
return stream;
}
});
}
private class UnauthorizedPredicate<R extends Response<?>> implements Predicate<R> {
private UserRepository mUserRepository;
private UnauthorizedPredicate(UserRepository userRepository) {
mUserRepository = userRepository;
}
#Override
public boolean test(R response) throws Exception {
if (response.code() == HttpCode.UNAUTHORIZED_HTTP_CODE) {
throw new SessionExpiredException();
}
if (response.body() == null) {
throw new HttpException(response);
}
Class<?> responseBodyClass = response.body().getClass();
if (responseBodyClass.isAssignableFrom(TokenInfo.class)) {
try {
mUserRepository.validateUserAccess((TokenInfo) response.body());
} catch (UnverifiedAccessException error) {
throw new SessionExpiredException(error);
}
}
return true;
}
}
}
I`ve written the custom operator, which makes next actions:
first request started, and we get 401 response code;
then we execute /refresh_token request to update the token;
after that if the token is refreshed successfully, we repeat the
first request. if /refresh_token token is failed, we throw exception
Then, you can easy implement it in the any request like that:
Observable
.compose(new RefreshTokenResponseTransformer<Response<{$your_expected_result}>>
(mApiService, mUserRepository()));
One more important thing:
Most likely, that your initial observable for retrofit has params, like that:
mApiService.someRequest(token)
if the param is expected to change during the performing RefreshTokenTransformer(e.g. /refresh_token request will get new access token and you save it somewhere, then you want to use a fresh access token to repeat the request) you will need to wrap your observable with defer operator to force the creating of new observable like that:
Observable.defer(new Callable<ObservableSource<Response<? extends $your_expected_result>>>() {
#Override
public Response<? extends $your_expected_result> call() throws Exception {
return mApiService.someRequest(token);
}
})
I think it does not need to use interceptor instead you implement Authenticator by which you can access refreshed token and okhttp automatically will handle that. if you get 401 it updates header with refreshed token and make new request.
public class TokenAuthenticator implements Authenticator {
#Override
public Request authenticate(Proxy proxy, Response response) throws IOException {
// Refresh your access_token using a synchronous api request
newAccessToken = service.refreshToken();
// Add new header to rejected request and retry it
return response.request().newBuilder()
.header(AUTHORIZATION, newAccessToken)
.build();
}

Retrofit sends multiple requests

I'm using retrofit 2 in my application. In application there's an authorization. All works right, but there is one problem still left. I have access_token and refresh_token. When I'm login in app I get my tokens. When my access_token expires I can get the new one with refresh token. If the refresh token expires too, I'm authorizing again for getting new tokens.
In my case when retrofit need to send call for updating my tokens, I sends data multiple times. What can be the cause of this?
private ApiClient(String endpoint) {
OkHttpClient.Builder client = new OkHttpClient.Builder()
.readTimeout(10, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS);
client.addInterceptor(new Interceptor() {
#Override
public Response intercept(#NonNull Chain chain) throws IOException {
Request request = chain.request();
request = request.newBuilder()
.header("Cache-Control", "public, max-age=0")
.build();
return chain.proceed(request);
}
});
supportopApi = new Retrofit.Builder()
.baseUrl(endpoint)
.client(client.build())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(SupportopApi.class);
}
public static synchronized void initializeInstance(String endpoint) {
if (instance == null) {
instance = new ApiClient(endpoint);
}
}
public static synchronized ApiClient getInstance() {
if (instance == null) {
throw new IllegalStateException("PentairAPIClient has not been initialized.");
}
return instance;
}
I don't want to add a big code here, so I can to add the update part too.
public void updateToken() {
//Perform this call if access token is expired
final ApiClient apiClient = ApiClient.getInstance();
SupportObjToken supportObjToken = new SupportObjToken();
//Here I'm setting my user information for request
supportObjToken.setGrantType("refresh_token");
supportObjToken.setClientId(SharedPreferencesManager.getInstance().getUserData().getClientId());
supportObjToken.setClientSecret(SharedPreferencesManager.getInstance().getUserData().getClientSecret());
supportObjToken.setRefreshToken(SharedPreferencesManager.getInstance().getUserData().getRefreshToken());
//This request calls multiple times (2-3 times or more)
Call<RefreshTokenActivation> newToken = apiClient.newToken(supportObjToken);
newToken.enqueue(new Callback<RefreshTokenActivation>() {
#Override
public void onResponse(Call<RefreshTokenActivation> call, Response<RefreshTokenActivation> response) {
if (response.isSuccessful()) {
String newAccessToken = response.body().getAccessToken();
String newRefreshToken = response.body().getRefreshToken();
Here I'm saving my updated access_token
UserData userData = SharedPreferencesManager.getInstance().getUserData();
SharedPreferencesManager.getInstance().removeUser();
userData.setAccessToken(newAccessToken);
userData.setRefreshToken(newRefreshToken);
SharedPreferencesManager.getInstance().setUser(userData);
tokenUpdaterCallback.updateToken();
} else {
if (response.code() == 401) {
//Perform this call if refresh token is expired
//This request is called multiple times too
Call<TokenActivation> token = apiClient.getToken("password",
SharedPreferencesManager.getInstance().getUserData().getClientId(),
SharedPreferencesManager.getInstance().getUserData().getClientSecret(),
SharedPreferencesManager.getInstance().getUserData().getEmail(),
SharedPreferencesManager.getInstance().getUserData().getPassword());
token.enqueue(new Callback<TokenActivation>() {
#Override
public void onResponse(Call<TokenActivation> call, Response<TokenActivation> response) {
if (response.isSuccessful()) {
String access_token = response.body().getAccessToken();
String refresh_token = response.body().getRefreshToken();
UserData userData = SharedPreferencesManager.getInstance().getUserData();
SharedPreferencesManager.getInstance().removeUser();
userData.setAccessToken(access_token);
userData.setRefreshToken(refresh_token);
SharedPreferencesManager.getInstance().setUser(userData);
//tokenUpdaterCallback goes to main class and repeats the authorization request
tokenUpdaterCallback.updateToken();
}
}
#Override
public void onFailure(Call<TokenActivation> call, Throwable t) {
Toast.makeText(context, "An error occurred", Toast.LENGTH_SHORT).show();
}
});
}
}
}
#Override
public void onFailure(Call<RefreshTokenActivation> call, Throwable t) {
Toast.makeText(context, "Response is not successful", Toast.LENGTH_SHORT).show();
}
});
}
What can be the problem?

Why is method not returning true?

I have an HTTP request inside of a method and i'm trying to return true/false based on the response from the request. im not sure what im doing wrong, I thought it was pretty straight forward. in the test scenario the condition inside of the onResponse call returns true. not sure whats getting lost in translation.
Also, in the final condition, the "message" variable is purple, in android studio, im not sure what this indicates. I think its related to my issue. suggestions?
public class DeleteButtonChecker {
public String message = new String();
public Boolean doCheck(int userID, int postID){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
RequestInterface requestInterface = retrofit.create(RequestInterface.class);
Call<ServerResponse> response = requestInterface.check(postID, userID);
response.enqueue(new Callback<ServerResponse>() {
#Override
public void onResponse(Call<ServerResponse> call, Response<ServerResponse> response) {
ServerResponse resp = response.body();
if(resp.getResult().equals(Constants.SUCCESS)){
message = "true";
} else {
message = "false";
}
}
#Override
public void onFailure(Call<ServerResponse> call, Throwable t) {
}
});
if(message.equals("true")) {
return true;
} else{
return false;
}
}
}
The response is handled asynchronously. On the line:
response.enqueue(new Callback<ServerResponse>() {
...
You are simply giving a callback to be executed once the response is returned. However the method is not blocked and continues to the next statement - which is the:
if(message.equals("true")) {
Which can be translated to:
if("".equals("true")) {
An asynchronous request cannot be treated as a synchronous call, that is given your conditions.
If it was for me I would use RxJava 2 Single with Retrofit to return a usable result from the request.
Check this out: https://github.com/square/retrofit/tree/master/retrofit-adapters/rxjava2
And make sure to learn some RxJava which can help you on the road

Categories

Resources