Retrofit 2 - null response body - android

I am trying to convert following response with Retrofit 2
{
"errorNumber":4,
"status":0,
"message":"G\u00f6nderilen de\u011ferler kontrol edilmeli",
"validate":[
"Daha \u00f6nceden bu email ile kay\u0131t olunmu\u015f. L\u00fctfen giri\u015f yapmay\u0131 deneyiniz."
]
}
But I am allways getting null response in onResponse method. So I tried to look at error body of the response with response.errorBody.string(). Error body contains exactly same content with raw response.
Here is my service method, Retrofit object and response data declerations:
#FormUrlEncoded
#POST("/Register")
#Headers("Content-Type: application/x-www-form-urlencoded")
Call<RegisterResponse> register(
#Field("fullName") String fullName,
#Field("email") String email,
#Field("password") String password);
public class RegisterResponse {
public int status;
public String message;
public int errorNumber;
public List<String> validate;
}
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
final String content = UtilityMethods.convertResponseToString(response);
Log.d(TAG, lastCalledMethodName + " - " + content);
return response.newBuilder().body(ResponseBody.create(response.body().contentType(), content)).build();
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
domainSearchWebServices = retrofit.create(DomainSearchWebServices.class);
I have controlled response JSON with jsonschema2pojo to see if I modled my response class wright and it seems OK.
Why Retrofit fails to convert my response?
UPDATE
For now as a work around I am building my response from error body.

I have solved the problem. When I make a bad request (HTTP 400) Retrofit doesn't convert the response. In this case you can access the raw response with response.errorBody.string(). After that you can create a new Gson and convert it manually:
if (response.code() == 400 ) {
Log.d(TAG, "onResponse - Status : " + response.code());
Gson gson = new Gson();
TypeAdapter<RegisterResponse> adapter = gson.getAdapter(RegisterResponse.class);
try {
if (response.errorBody() != null)
registerResponse =
adapter.fromJson(
response.errorBody().string());
} catch (IOException e) {
e.printStackTrace();
}
}

Related

Android Retrofit (POST) - Expected BEGIN_OBJECT but was STRING at line 2 column 1 path $

I'm trying to send to the server a simple POST message with x-www-form-urlencoded and with Retrofit library.
This is my interface:
public interface MyApiEndpointInterface {
#FormUrlEncoded
#Headers({"Authorization: Bearer f2cb65f2a243453465346346543gdf5643543gfd"})
#POST("Sync/syncToServer")
Call<SyncResponse> syncToServer(#Field("name") String name, #Field("func") String func,
#Field("func_params[]") JSONArray func_params, #Field("auth") String auth,
#Field("local_db_ver") String local_db_ver);
}
And this is how I send the JSONArray and all the other parameters to the server:
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
MyApiEndpointInterface apiService =
retrofit.create(MyApiEndpointInterface.class);
String func_params_obj = "{tableName:user_presence,userId:1156,productType:3}";
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(func_params_obj);
} catch (JSONException e) {
e.printStackTrace();
}
JSONArray jsonArray = new JSONArray();
jsonArray.put(jsonObject);
Call<SyncResponse> call = apiService.syncToServer("Sync","syncToServer", jsonArray,"true","10");
call.enqueue(new Callback<SyncResponse>() {
#Override
public void onResponse(Call<SyncResponse> call, Response<SyncResponse> response) {
int statusCode = response.code();
SyncResponse syncResponse = response.body();
Log.d("SyncResponse","onResponse,statusCode=" + statusCode);
}
#Override
public void onFailure(Call<SyncResponse> call, Throwable t) {
// Log error here since request failed
Log.d("SyncResponse","onFailure=" + t.getMessage());
}
});
When I look at the logs of the server I see that all the parameters are set correctly except the JSONArray that is set to an array of strings instead of an array of objects (JSONObject) and this whey I always get to onFailure with the error: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 2 column 1 path $
This is how I get this on the server (as you can see it's a string and not a JSONObject):
array (
0 => '
{
"tableName": "products",
"userId": 1156,
"productType": 3
}
',
)
I hope that I explain myself ok and thanks for the help

Android RetroFit: 400 Response

I am plugging Retrofit into my android app.
Here is how I build retrofit, notice the interceptor for the logging and headers.
public void buildRetrofit(String token){
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addNetworkInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.header("api-version", "1")
.method(chain.request().method(), chain.request().body())
.build();
return chain.proceed(newRequest);
}
});
httpClient.addInterceptor(logging);
Retrofit.Builder buidler = new Retrofit.Builder()
.baseUrl("XXX_HIDDEN_FORSTACKOVERFLOW")
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build());
retroFit = buidler.build();
}
I make the call like so
OrderApi orderApi = mainActivity.retroFit.create(OrderApi.class);
Call<Order> call = orderApi.getOpenOrder();
call.enqueue(new Callback<Order>() {
#Override
public void onResponse(Call<Order> call, Response<Order> response) {
Order a = response.body();
int b = 1;
}
#Override
public void onFailure(Call<Order> call, Throwable t) {
}
});
And here is how the actual request tag
public interface OrderApi {
#POST("/HIDDEN")
Call<Order> getOpenOrder();
}
Lastly, here is the order class
public class Order {
private String orderId;
private OrderStatus orderStatus;
public String getOrderId(){
return orderId;
}
public OrderStatus getOrderStatus() {
return orderStatus;
}
}
I get a response of 400. I have no idea why, and It works in postman etc. Something to note is that the response contains a lot more properties than just the ones in the class. I just want a proof on concept, but that shouldn't break things right?
.................
Managed to fix it. Had to send an empty body request as it was a post but I wasn't posting anything. API is dumb.
See here to send empty request Send empty body in POST request in Retrofit

How to send Token in Header to server in Android

In my application I want to create a Login/Register page.
In the login page I send the Username, Password, Token from client to Server.
I should get Username and Password from USER, and get Token from HEADER of Request.
For connect client to server I use Retorfit 2.2.0 library.
Code from the Interface class :
#POST("User/Authenticate")
Call<LoginResponse> getLoginResponse(#Header("Token") String token, #Body LoginDatum loginDatum);
Code within the Activity :
public void getLogin(String username, String password) {
final LoginDatum loginDatum = new LoginDatum();
loginDatum.setUsername(username);
loginDatum.setPassword(password);
InterfaceApi api = ApiClient.getClient().create(InterfaceApi.class);
Call<LoginResponse> call = api.getLoginResponse(sendToken, loginDatum);
Log.e("tokenTAG", "Token : " + sendToken);
call.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
LoginResponse loginResponse = response.body();
String token = response.headers().get("Token");
if (token != null) {
sendToken = token;
Log.e("tokenTAG", "Token : " + sendToken);
}
if (loginResponse.getStatusCode() == 200) {
Toasty.success(context, context.getResources().getString(R.string.welcome) + " " +
loginResponse.getData().getName(), Toast.LENGTH_LONG, true).show();
} else {
Toasty.error(context, loginResponse.getStatusMessage() + "", Toast.LENGTH_LONG, true).show();
}
loadProgress.get(0).setVisibility(View.GONE);
loginBtn.setVisibility(View.VISIBLE);
btnShadow.setVisibility(View.VISIBLE);
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
loadProgress.get(0).setVisibility(View.GONE);
loginBtn.setVisibility(View.VISIBLE);
btnShadow.setVisibility(View.VISIBLE);
Toasty.error(context, context.getResources().getString(R.string.failRequest),
Toast.LENGTH_LONG, true).show();
}
});
}
And show me this in LogCat :
tokenTAG: Token : null
tokenTAG: Token : MKGKFPOVRMU4MRK0STNDO20RA2MPEWT7Y1N2WUM5QLIXJX2TEOM9APGUTYJMD8R42WFVESD8GRXCTCINA2LZKU7JV2I7KA2R4N5W
But when I want to send the token with this code : Call<LoginResponse> call = api.getLoginResponse(sendToken, loginDatum); it shows me null.
I have use this line : Call<LoginResponse> call = api.getLoginResponse(sendToken, loginDatum); to generate the request callBack, although this line Token is not NUll.
How can I fix it?
if you use Retrifit get onNetwork request,in order to add Header to your requese,you must be write an Intercepter.
just replace getClient menthod with this one
public static Retrofit getClient(final Context context) {
if (retrofit == null) {
Log.d("AuthTokenTest", "getClient: null");
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
dispatcher = new Dispatcher();
httpClient.dispatcher(dispatcher);
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Log.d("INTERCEPTOR", original.url().toString());
//System.out.print(original.toString());
Request request;
user=User.getLoggedInUserInstance(context);
String authToken="";
if(user!=null)
authToken=user.getAuthToken();
Log.d("AuthTokenTest", "intercept: authtoken:"+authToken);
request = original.newBuilder()
.header("X-AUTH-TOKEN", authToken)
.header("x-requested-with", "XMLHttpRequest")
.method(original.method(), original.body())
.build();
okhttp3.Response response = chain.proceed(request);
Log.d("INTERCEPTOR-", "response_code: "+response.code());
// Log.d("INTERCEPTOR", response.body().string());
return response;
}
});
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
if(BuildConfig.DEBUG){
//print the logs in this case
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
}else{
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
}
httpClient.addInterceptor(loggingInterceptor);
OkHttpClient client = httpClient.build();
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
.setLenient()
.create();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
let me know if this solution works or not

HTTP response is empty

I am using okHTTP to make an https call to a nodejs/express server. The server returns a json string
{"result" : true}
This json string is shown as {"result":true} in the browser, however when I try to read the response using OkHTTp, I get the following response:
<h1>Not Found</h1>
<h2></h2>
<pre></pre>
There is no json response to be found. Here is the Okhttp code I am using.
public static void sendCredentialsWithPost(LinkedHashMap<String, String> data, String serverUrl, Callback callback) {
Object[] keys = data.keySet().toArray();
FormBody.Builder formBodyBuilder = new FormBody.Builder();
for(Object k : keys) {
String key = (String) k;
formBodyBuilder.add(key, data.get(key).toString());
}
RequestBody formBody = formBodyBuilder.build();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(serverUrl)
.post(formBody)
.build();
Log.e("wingoku", "url is: "+ serverUrl);
client.newCall(request).enqueue(callback);
}
This is the code for parsing the okhttp response:
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
String serverResponse = response.body().string();
}
What am I doing wrong? How can I fix it?

How to get response body in okhttp when code is 401?

I am using OkHttp 3.2.0 and here is code for building request object:
MediaType JSON = MediaType.parse(AppConstants.CONTENT_TYPE_VALUE_JSON);
RequestBody body = RequestBody.create(JSON, requestBody);
HttpUrl url = new HttpUrl.Builder()
.scheme("http")
.host("192.168.0.104")
.port(8080)
.addPathSegment("mutterfly-server")
.addPathSegment("j_spring_security_check")
.addQueryParameter("j_username", jsonObject.getString("emailId"))
.addQueryParameter("j_password", jsonObject.getString("password"))
.build();
request = new Request.Builder()
.addHeader(AppConstants.CONTENT_TYPE_LABEL, AppConstants.CONTENT_TYPE_VALUE_JSON)
.addHeader(AppConstants.ACCEPT_LABEL, AppConstants.CONTENT_TYPE_VALUE_JSON)
.url(url)
.post(body)
.build();
And here is how I parse the response:
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
String respBody;
if (response.isSuccessful()) {
if (response.body() != null) {
respBody = response.body().string();
Log.i(TAG, respBody);
response.body().close();
if (AppMethods.checkIfNull(loginParserListener)) {
try {
final VUser user = AppMethods.getGsonInstance().fromJson(respBody, VUser.class);
} catch (Exception e) {
}
}
}
} else {
switch (response.code()){
case 401:
String body="HTTP_UNAUTHORIZED";
break;
}
}
}
});
This is the ideal response(from web rest client) when authentication is failed.
{"msgDesc":"The username or password you entered is incorrect..","statusCode":401}
EDIT:
response.toString() returns
Response{protocol=http/1.1, code=401, message=Unauthorized, url=http://192.168.0.104:8080/mutterfly-server/j_spring_security_check?j_username=s#s.s&j_password=1}
response.body().toString() returns
okhttp3.internal.http.RealResponseBody#528ae030
I want to fetch the msgDesc which is in response body. Is there any method which will return this string?
Try this:
switch (response.code()){
case 401:
JsonObject object=new JsonObject(response.body().string());
String body=object.getString("msgDesc");
break;
}
It's quite weird but Square, the company behind OkHttp, has chosen to not use 'toString()' but 'string()' as method for getting the body as a String.
So this works;
String string = response.body().string();
//convert to JSON and get your value
But this doesn't:
String string = response.body().toString();
401 means permission denied.
Check if your token is valid or user/password is correct.

Categories

Resources