Access sent parameter in onResponse of retrofit 2 - android

I create a request with retrofit2 and send parameter to server, how can access sent parameter in onResponse?
retrofit = new Retrofit.Builder()
.baseUrl("baseAddress")
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiBase serviceSetParam = retrofit.create(ApiBase.class);
Call<String> myCall = serviceSetParam.setParam("data1","data2");
Callback<String> myCallback = new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
//i need access data1 & data2 Here !
if (response.isSuccessful()) {
String mResponse= response.body();
} else {
Utils.Log("unSuccessful");
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Utils.Log("onFailure");
}
};
myCall.enqueue(myCallback);
here the send param method:
#FormUrlEncoded
#POST("set")
Call<String> setParam(#Field("param1") String param1, #Field("param2") String param2);

in onResponse method of your request, test this code:
try {
BufferedSink bf = new Buffer();
call.request().body().writeTo(bf);
Log.i("params are",bf.buffer().readUtf8().toString());
} catch (IOException e) {
e.printStackTrace();
}

You need to get the original Request from OkHttp.
List<String> pathSegments = original(response.raw()).url().pathSegments();
given:
static Request original(Response response) {
while (true) {
Response prior = response.priorResponse();
if (prior == null) {
break;
}
response = prior;
}
return response.request();
}

Related

Retrofit 2 - string error body is empty

Server returns JSON object in case of success and simple String for error case.
There are no problems with parsing JSON into object. The problem rises when I want to parse error since the response.errorBody().string() is empty.
When I send the same request using Postman the response as follows:
And I can't read this error... Anyone faced such problem?
Code code
gradle:
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.okhttp:okhttp:2.6.0'
RestClient.java:
private static GitApiInterface gitApiInterface;
...
public static GitApiInterface getClient() {
if (gitApiInterface == null) {
OkHttpClient okClient = new OkHttpClient();
okClient.interceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
return response;
}
});
Retrofit client = new Retrofit.Builder()
.baseUrl(URL_BASE)
.addConverterFactory(GsonConverterFactory.create())
.build();
gitApiInterface = client.create(GitApiInterface.class);
}
return gitApiInterface;
}
ApiInterface.java:
public interface ApiInterface {
#POST("/register/user/{email}/")
Call<User> postRegisterUser(#Path(value = "email", encoded = true) String email,
#Query("firstname") String firstName,
#Query("lastname") String lastName,
#Query("country") String country,
#Query("phone") String phone,
#Query("deviceid") String deviceId);
...
ServerRequests.java:
public void registerUser(#NonNull String email,
#NonNull String firstName,
#NonNull String lastName,
#NonNull String country,
#NonNull String phone,
#NonNull String deviceId,
#NonNull final RegisterUserCallback callback) {
showProgressBar();
RestClient.GitApiInterface service = RestClient.getClient();
Call<User> call = service.postRegisterUser(email, firstName, lastName, country, phone, deviceId);
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
hideProgressBar();
User user = response.body(); //this works great
if (response.isSuccess()) {
Log.d(TAG, "REGISTER success: " + response.message());
callback.onRegisteredUser(user);
} else {
try {
Log.e(TAG, "REGISTER fail: " + response.errorBody().string()); //empty error body
callback.onRegisterFailed(response.errorBody().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<User> call, Throwable t) {
hideProgressBar();
callback.onRegisterFailed("error");
}
});
}
My answer is based on HttpLoggingInterceptor class.
I wrote getStatusError() method by given in parameter response.errorBody().
private StatusError getStatusError(ResponseBody responseBody) {
StatusError statusError = null;
if (responseBody != null) {
try {
BufferedSource source = responseBody.source();
if (source != null) {
source.request(Long.MAX_VALUE); // Buffer the entire body.
Buffer buffer = source.buffer();
Charset charset = UTF8;
MediaType contentType = responseBody.contentType();
if (contentType != null) {
charset = contentType.charset(UTF8);
}
String string = buffer.clone().readString(charset);
if (!TextUtils.isEmpty(string)) {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
statusError = gson.fromJson(string, StatusError.class);
}
}
} catch (Exception e) {
LogUtils.LOGW(TAG, "Impossible to get StatusError stream", e);
}
}
return statusError;
}
StatusError is a POJO class to map (JSON) elements:
public class StatusError {
#SerializedName("message")
public String message;
#SerializedName("errors")
public ArrayList<ErrorDetail> errors;
}

Simple login form with Retrofit

I'm starting to work with Retrofit but I'm stuck on this simple step. I have a login form and I'm trying to authenticate with the server but I just can't send the request.
This is what I've tried:
My Retrofit client:
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
My login interface:
public interface Login {
#POST(LOGIN)
Call<String> loginWithCredentials(#Body LoginCredentials data);
}
The LoginCredentials class:
public class LoginCredentials {
private String name;
private String pass;
public LoginCredentials(String name, String pass) {
this.name = name;
this.pass = pass;
}
}
And the part where I call it:
#Override
public void onClick(View v) {
showProgress(true);
String username = userField.getText().toString();
String password = passField.getText().toString();
ApiController.Login loginClient = ApiController.createService(ApiController.Login.class);
Call<String> call =loginClient.loginWithCredentials(new LoginCredentials(username, password));
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
handleResponse(response.body());
}
#Override
public void onFailure(Call<String> call, Throwable t) {
showProgress(false);
Log.e(TAG, t.getLocalizedMessage());
}
});
}
And I keep getting the error Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $but I have no idea what it means.
I figured it out. It was easier than I thought. You can skip the parsing that Retrofit does by setting the response type of the method as ResponseBody. Them you just need to read the response and use the string() method that provides. That's it!
Example:
public interface Login {
#POST(LOGIN)
Call<ResponseBody> loginWithCredentials(#Body LoginCredentials data);
}
Then use like this:
String username = userField.getText().toString();
String password = passField.getText().toString();
ApiController.Login loginClient = ApiController.createService(ApiController.Login.class);
Call<ResponseBody> call = loginClient.loginWithCredentials(new LoginCredentials(username, password));
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
// get String from response
String stringResponse = response.body().string();
// Do whatever you want with the String
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
// handle error
}
});
This error means that gson trying to parse string from server as JSON object and can't find the opening bracket.
I think you could return actual JSON from server like
{"api_token": "token"}
Also this bug could possibly be solved by importing latest GSON version mentioned here

Receiving an empty body in retrofit Response

I am using retrofit to get data from http URL.
My Interface Class :
public interface SlotsAPI {
/*Retrofit get annotation with our URL
And our method that will return a Json Object
*/
#GET(url)
retrofit.Call<JSONObject> getSlots();
}
My request method.
public void getResponse(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
//Creating an object of our api interface
SlotsAPI api = retrofit.create(SlotsAPI.class);
retrofit.Call<JSONObject> callback = api.getSlots();
callback.enqueue(new Callback<JSONObject>() {
#Override
public void onResponse(Response<JSONObject> response) {
if (response != null) {
Log.d("OnResponse", response.body().toString());
}
}
#Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
});
}
In the response I am receiving an empty body.And the server responds with 200 OK.
D/OnResponse: {}
But when I open the URL in browser I am getting JSONObject on the screen.
you should try like this way ....
public interface SlotsAPI {
/*Retrofit get annotation with our URL
And our method that will return a Json Object
*/
#GET(url)
Call<JsonElement> getSlots();
}
in request method
retrofit.Call<JsonElement> callback = api.getSlots();
callback.enqueue(new Callback<JsonElement>() {
#Override
public void onResponse(Response<JsonElement> response) {
if (response != null) {
Log.d("OnResponse", response.body().toString());
}
}
Please check your JsonObject. If you want to get response in json you must be define a response type JsonObject not JSONObject other wise specify the pojo class in your interface.
I think you are not understanding the retrofit filosofy.
The correct interface should be:
public interface SlotsAPI {
/*Retrofit get annotation with our URL
And our method that will return a Json Object
*/
#GET(url)
JSONObject getSlots();
}
When you call the getSlots method, retrofit will automatically do the HTTP request and return the JSONObject.
You will need to do this out of the main thread.
Make sure that the url of #Get is relative path
#Base URL: always ends with /
#Url: DO NOT start with /
Example:
String URL = http://api.co/base/ ;
And
#GET("webservice/syncdown")
JSONObject getSlots();
You may receiving a list of Slots. the Gson converter will handle it if you sending array of json
#GET(url)
retrofit.Call<List<Slot>> getSlots();
You are using the retrofit 2 or 1? The version 2 still is in beta.
If you are using the version 1. Use this:
public interface SlotsAPI {
/*Retrofit get annotation with our URL
And our method that will return a Json Object
*/
#GET(url)
void getSlots(Callback<JsonElement> callback);
}
With this the call will be asynchronous.
Same problem here, and answer from curiousMind saved my day.
More on the same subject: if you need to get a value from a pair use:
String value = response.body().getAsJsonObject().get("pair_name").getAsString();
Call<Void> getSlots() worked for me.
private void APIRetrofit_method() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RecyclerInterface.JSONURL)
// .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
RecyclerInterface api = retrofit.create(RecyclerInterface.class);
Call<ResponseBody> call = api.getString(); /// GET METHOD without passing params
// Post METHOD CODE START
// HashMap<String, String> params = new HashMap<String, String>();
// params.put("name", "yuva");
// params.put("pass", "" + "123");
// Call<ResponseBody> call1 = api.getProspectList(params);
// Post METHOD CODE END
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
Log.d(TAG, "GetProspectlistresponse" + "" + response.isSuccessful());
utility.hideProgressDialog();
if (response.isSuccessful()) {
String remoteResponse = new String(response.body().string());
Log.d(TAG, "Holidaylistresponse" + "" + remoteResponse);
try {
JSONObject object = new JSONObject(remoteResponse);
JSONArray array = object.getJSONArray("Holidays_Details");
if (array.toString().equals("[]")) {
holiday_recyclerView.setVisibility(View.GONE);
} else {
holiday_recyclerView.setVisibility(View.VISIBLE);
for (int i = 0; i < array.length(); i++) {
JSONObject c = array.getJSONObject(i);
String holidayDate = c.getString(TAG_HOLIDAYDATE);
String holidayName = c.getString(TAG_HOLIDAYName);
String holidaytype = c.getString(TAG_HOLIDAYtype);
HashMap<String, String> customers = new HashMap<String, String>();
customers.put(TAG_HOLIDAYDATE, holidayDate);
customers.put(TAG_HOLIDAYName, holidayName);
customers.put(TAG_HOLIDAYtype, holidaytype);
arrayList.add(customers);
}
getHolidaylistAdapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
utility.hideProgressDialog();
}
} catch (IOException e) {
e.printStackTrace();
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("ErrorResponsestring", call.toString());
}
});
}
String JSONURL = "https://demonuts.com/Demonuts/JsonTest/Tennis/";
#GET("json_parsing.php")
Call<ResponseBody> getString();
// #POST("getProspectList")
// #FormUrlEncoded
// Call<ResponseBody> getProspectList(#FieldMap HashMap<String, String> body);
implementation 'com.squareup.retrofit2:retrofit:2.0.2'
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
implementation 'com.squareup.okhttp3:okhttp:4.0.0'

Retrofit - POST request with #Path and without parameters

The request to API as follows:
POST /verify/phone/{userid}/
Mandatory parameters: userid (integer)
Return: nothing
I receive Bad Request error all the time if I want to verify user with id 1 (for example):
Response{protocol=http/1.1, code=400, message=Bad Request, url=http://dummyapi.com/verify/phone/1/}
Posting the same request using Postman works well.
Code:
#POST("/verify/phone/{userid}/")
Call<String> postVerifyPhone(#Path("userid") int userId);
public void postVerifyPhone(int userID){
showProgressBar();
RestClient.GitApiInterface service = RestClient.getClient();
Call<String> call = service.postVerifyPhone(userID);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response) {
hideProgressBar();
if (response.isSuccess()) {
String result = response.body();
} else {
Log.d("Fail: ", response.body()); //everytime here with Bad Request
}
}
#Override
public void onFailure(Throwable t) {
hideProgressBar();
}
});
}
I'm using String as the return type since there's message returned when there're no user with requested ID in db.
What could be a cause?
I am calling below code for reading response data.
public void postVerifyPhone(int userID){
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(Constants.URL).build();
RetrofitApi retrofitApi = restAdapter.create(RetrofitApi.class);
retrofitApi.postVerifyPhone(userID, new Callback<Response>() {
#Override
public void success(Response response, Response response2) {
BufferedReader reader = null;
StringBuilder sb = new StringBuilder();
try {
reader = new BufferedReader(new InputStreamReader(response.getBody().in()));
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
String result = sb.toString();
// System.out.println("res:" + result.toString());
}
#Override
public void failure(RetrofitError error) {
hidePDialog();
}
});
}
below is postVerifyPhone() code
#FormUrlEncoded
#POST("/verify/phone/")
public void postVerifyPhone(#Field("userID") String userID, Callback<Response> resonse);
It is working fine for me.please check it once.
I think the right annotation is #PathParam, not #Path

Retrofit POST raw string body

I am using Retrofit to send a POST request to a server. The body of the POST must be in the form jdata={"key1":"value1",...} along with a Content-Type header set to application/x-www-form-urlencoded. I found a similar question but the accepted answer is not working.
Here's what I tried -
My interface
public interface APIHandler {
#Headers("Content-Type: application/x-www-form-urlencoded")
#FormUrlEncoded
#POST(URL)
Call<ResponseBody> getdata(#Field("jdata") String jdata);
}
Call function
public void load() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("BASE_URL")
.addConverterFactory(GsonConverterFactory.create())
.build();
// prepare call in Retrofit 2.0
APIHandler iAPI = retrofit.create(APIHandler.class);
String requestBody = "{\"id\":\"value\",\"id1\":\"value2\"}"
Call<ResponseBody> call = iAPI.getData(requestBody);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> c, Response<ResponseBody> response) {
if (response.isSuccess()) {
ResponseBody result = response.body();
String gs = new Gson().toJson(result);
Log.d("MainActivity", "response = " + gs + " status: " + statusCode);
} else {
Log.w("myApp", "Failed");
}
}
#Override
public void onFailure(Call<ResponseBody> c, Throwable t) {
}
});
}
But I receive response = null and status = 200. What am I doing wrong? The expected response is only a string and not a JSON array.
I am leaving this here so that it helps someone.
The above code is correct. As I mentioned in the last line, a plain string response was expected. But since it is not a JSON response, the conversion probably did not work and the response was null. The only solution I could find was to directly convert the response to string -
try {
stresp = response.body().string()
Log.d("MainActivity", "response = " + stresp + " status: " + statusCode);
} catch (IOException e) {
//Handle exception
}
There might be a better way to handle this but that worked for me!
You can use like that. I have tested this and it working fine
public interface APIHandler {
#POST(URL)
Call<ResponseBody> getdata(#Body JsonObject body);
}
Request body:
JsonObject requestBody = new JsonObject();
requestBody.addProperty("id", "value1");
requestBody.addProperty("id1", "value2");
Prepare call in Retrofit 2.0
APIHandler iAPI = retrofit.create(APIHandler.class);
And Call function :
Call<ResponseBody> call = iAPI.getData(requestBody);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> c, Response<ResponseBody> response) {
if (response.isSuccess()) {
String result = response.body().string();
Log.d("MainActivity", "response = " + result);
} else {
Log.w("myApp", "Failed");
}
}
#Override
public void onFailure(Call<ResponseBody> c, Throwable t) {
}
});

Categories

Resources