I get error when I try to make request with retrofit in my android application.
I get 500 Interval Server Error
"title":"Internal Server
Error","status":500,"detail":"JSONObject[\"response\"] not
found.","path":"/api/profiles/help/45.13367991428822/33.5960291326046","message":"error.http.500"
Here is my code:
IApiService service = RetrofitInstance.getRetrofitAuthInstance().create(IApiService.class);
Call<ArrayList<Profile>> call = service.sendHelp(v1, v2);
call.enqueue(new Callback<ArrayList<Profile>>() {
#Override
public void onResponse(Call<ArrayList<Profile>> call, Response<ArrayList<Profile>> response) {
Toast.makeText(getBaseContext(), String.valueOf(response.code()), Toast.LENGTH_LONG).show();
}
#Override
public void onFailure(Call<ArrayList<Profile>> call, Throwable t) {
Toast.makeText(getBaseContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
And my Interface:
#GET(Urls.SEND_HELP)
Call<ArrayList<Profile>> sendHelp(#Path("latitude") String latitude,
#Path("longitude") String longitude);
Please, help me.
Obviously problem is with object serialization on server side.
Status code 5xx stands for error that happened on server.
There is nothing you can do with your Retrofit client to fix it.
Related
I know there are lots of tutorials for OkHttp, but basically all of them do something different in the onResponse method and most don't bother to explain why. Some check for if (response.isSuccessful), some surround it with try/catch, some don't do any of this at all.
This is my example project. What is the proper way to handle the onResponse method?
public class MainActivity extends AppCompatActivity {
private TextView textViewResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textViewResult = findViewById(R.id.text_view_result);
OkHttpClient client = new OkHttpClient();
String url = "https://reqres.in/api/users?page=2";
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textViewResult.setText(myResponse);
}
});
}
});
}
}
Update
onResponse of okhttp runs on background thread. So, yes, it's necessary to do MainActivity.this.runOnUiThread(...).
Original answer
onResponse callback already runs on ui thread AFAIK. So, you don't actually need to do MainActivity.this.runOnUiThread(...).
And everyone's onResponse is different because everyone has different needs. Use try/catch if your operations in onResponse might give error and you don't want it to crash.
For some network requests you may need to check if response is successful for other you may not. It all depends on use cases. Do what works for you best.
I'd suggest you surround your code in onResponse in a try/catch block because the user might close the app before the network request is finished. And when you set the textview text in onResponse it will crash because the activity and that textview doesn't exist anymore.
Adding to the answer from rafid. There are basically three cases you want to check.
response.isSuccessful() => status code between 200 and 300
response.code() => to manually check after response is not successful
onFailure() => Network error or parsing error etc.
Ideally your callback would handle those cases something like
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// network error or parsing error
}
#Override
public void onResponse(Call call, Response response) {
if (response.isSuccessful()) {
// do stuff all good
} else {
// handle different cases for different status codes or dump them all here
}
}
});
The reason you need a try-catch is because OkHttp is trying to parse the response. This is the case for example for response.errorBody().string();. Another case would be if your Callback<T> has actually a type parameter. Again OkHttp will try to parse the response to that type. If it fails it will result in a callback onto the onFailure method.
I think you need to make sure you know the legal response from the request, like an json or File. if it's just a json, use like below:
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
if (response.isSuccessful() && !TextUtils.isEmpty(myResponse)) {
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textViewResult.setText(myResponse);
}
});
}
}
Edit: To be more clear.
Callback is running in mainThread so there is no need to call runOnUiThread.
If response is not successful you can try to parse error body as below. If response is successful you can parse with Gson as i show.
String message = "";
if (response.errorBody() != null) {
try {
message = response.errorBody().string();
} catch (IOException ignored) {
Log.e("OkHttp IOException", "error while parsing response");
}
Log.d("Error Message", message);
}
I recommend you to use Gson Library. First you should create your pojo class. You can use http://www.jsonschema2pojo.org/ to create your pojo class. Then you can parse body like below
Gson gson = new Gson();
MyPojo myPojo = gson.fromJson(response.body().charStream(), MyPojo.class);
Im making an asynchronous call and im able to send a request to the server and getting my desired JSON(using postman) but for some reason the OnResponse and OnFailure methods are not being executed, may you please help me if im missing out something.Im using retrofit2
private List<Advert> getAdverts(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl( "http://192.168.100.4:8092/portal/")
.client(client.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestService requestService = retrofit.create(RequestService.class);
Call<List<Advert>> customerCall= requestService.getAdverts(accountNumber);
System.out.println("++++++++++++++ request was made +++++++++++++++++++");
customerCall.enqueue(new Callback<List<Advert>>() {
#Override
public void onResponse(Call<List<Advert>> call, Response<List<Advert>> response) {
Log.d("onResponse", "" + response.message());
System.out.println("++++++++++++++ was here+++++++++++++++++++");
if (response.isSuccessful()) {
adverts.addAll(response.body());
} else {
Toast.makeText(getContext(), "" + response.message(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<List<Advert>> call, Throwable t) {
Log.d("onFailure", t.toString());
}
});
return adverts;
}
Not sure, but you're returning before de operation has ended (as you mentioned is a asynchronous call). So as soon you enqueue, you're returning "adverts" (probably cancelling your call).
Consider using other alternatives to return your response, like Callbacks, EventBus, persist the response on local storage, etc.
I am implementation for Retrofit on api call using images-upload base64Encode string. it is sending data perfect but Retrofit return response Internal Server Error 500 and i am sending request type is Body custom class. Plz help me what i do.
#Headers("Accept:application/json")
#POST(RestClient.postRegister)
Call<RegisterResp> getRegisterResponse(#Body RequestRegisterVo requestRegisterVo);
Call<RegisterResp> call = MyApplication.getRestClient().getApplicationServices().getRegisterResponse(requestRegisterVo);
call.enqueue(new Callback<RegisterResp>() {
#Override
public void onResponse(Call<RegisterResp> call, Response<RegisterResp> response) {
if (Other.isValidResp(response)) {
// success Log.i(TAG,"Register successfully");
} else {
hideDialog();
}
}
#Override
public void onFailure(Call<RegisterResp> call, Throwable t) {
hideDialog();
showToast(t.getMessage());
}
});
The same issue I had to face it, I got a solution in my case-
there is parameter issue, I was sending parameters in String and at the backend, they required Integer parameters.
You also checkout may be there is the issue with parameters or second reason is the URL issue so check it URL also.
Before I get the obligatory "you shouldn't be testing real network responses for XYZ reasons!", it should be noted that I am not asking whether or not I should.
I am asking specifically how I would go about doing so, if I wanted to.
After a few hours of struggle I've successfully managed a proper response from Volley, and have that test going.
The problem I'm having now, is that call.enque(...) seems to hang on the RobolectricTestRunner. Unlike Volley, I can't peek in and see whats going on in there (for Volley, the challenge was not realizing that Looper.getMainLooper doesn't get properly created.)
So, all I am doing is trying to make a simple request to the server via Retrofit. The issue, as I said, is that the entire system hangs at call.enqueue, and there is no error or response ever (even when my await is longer). The network call works fine with volley, but I am getting this snag here with Retrofit. Here's the code if you want to try it. And of course, the function works fine when the app is running.
//in NetworkManager.class
public void someCall(HashMap properties, NetworkResponseListener listener){
this.okHttpClient = new OkHttpClient.Builder().cache(new Cache(appContext, 35 * 1024 * 1024)).build();
this.retrofit = new Retrofit.Builder().baseUrl(httpPath + apiHost).client(okHttpClient).build();
this.myService = retrofit.create(MyService.class);
Call call = myService.someRequest(properties);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
listener.onSuccess(response);
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
listener.onError(t);
}
});
}
Service:
interface MyService {
#GET("/api/SomeEndpoint/")
Call<ResponseBody> someRequest(#QueryMap Map<String, Object> params);
}
Test:
#Test
public void testSomeCall() throws Exception {
//Network class has setup OkHttpClient/Service/Retrofit already
NetworkResponseListener listener = new NetworkResponseListener() {
#Override
public void onSuccess(Response response) {
this.response = response;
}
#Override
public void onError(Throwable error) {
//
}
};
NetworkManager.someCall(this.properties, listener);
await().atMost(30, TimeUnit.SECONDS).until(ResponseReceived());
}
Everyone's response on stackoverflow has been 'don't test real network responses', which is really not helpful.
Solution is pretty much exactly the same as for volley.
Retrofit2 will default to the platform callback executor, which will not be correctly instantiated in a test.
Solution is simple. If you wish to test retrofit with real network calls, you must change the callbackExector. Here's what I ended up doing:
retrofit = new Retrofit.Builder().baseUrl(baseUrl)
.client(okHttpClient).callbackExecutor(Executors.newSingleThreadExecutor())
Network tests are running successfully.
I have created an app to use REST api developed by me. Android client is written with retrofit library.
there I have created an interface as ObjectIFaceAsync
public interface ObjectIFaceAsync {
#POST("/")
public void addArea(
#Body Area area,
Callback<JsonElement> data
);
}
then I implemented it in a button click
Area pojoArea = new Area();
pojoArea.setArea(area.getText().toString());
pojoArea.setDistrict(district.getText().toString());
pojoArea.setProvince(province.getText().toString());
pojoArea.setAreaType(areaType.getSelectedItem().toString());
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(URLs.ENDPOINT + "/restaddarea")
.build();
ObjectIFaceAsync objectIFaceAsync = restAdapter.create(ObjectIFaceAsync.class);
try {
objectIFaceAsync.addArea(
pojoArea, new Callback<JsonElement>() {
#Override
public void success(JsonElement jsonElement,retrofit.client.Response response) {
if (jsonElement.getAsJsonObject()
.get("status").getAsString().equals("s")) {
//show a message
} else {
//show another message
}
}
#Override
public void failure(RetrofitError retrofitError) {
//show a failure message
}
}
);
} catch (Exception e) {
}
I have used the same endpoint to and sent a get request that is not having a JSON #Body. It works fine. Here I always get an error. means it always runs the failure method. I got displayed the
retrofitError.getMessage();
and
retrofitError.getResponse().getStatuse();
They show null and 400 respectively.
Can someone tell what I have to do to get this corrected. or what I have done wrong here.
thanks.
Use
retrofitError.getBody()
to get String or
retrofitError.getBodyAs(MyError.class)
if you want to map the error json to object