I have written a Retrofit code which has a Yii2 backend. The problem is: when I call the web-service on backend, it works perfectly. However, when I try to call the web-service from android device; it throws a response code of 404. Here is what I have done:
I am targeting a url which looks like: http://192.168.0.104/root-web/web/index.php?r= and it had an end-point: root/register
public interface RegisterAPIService {
#POST("practice/register")
Call<RegisterModel> registerUser(#Body RegisterDetails registerDetails);
}
The code in my activity looks like this..
RegisterDetails registerDetails = new RegisterDetails(email, mobile, password);
RegisterAPIService registerAPIService = retrofit.create(RegisterAPIService.class);
Call<RegisterModel> call =registerAPIService.registerUser(registerDetails);
call.enqueue(new Callback<RegisterModel>() {
#Override
public void onResponse(Response<RegisterModel> response) {
Log.d("Message", "code..."+response.code() + " message..." + response.message()+" body..."+response.body());
}
#Override
public void onFailure(Throwable t) {
}
});
} else {
// Error
}
}
I am getting 404 for the above code. I am trying to send my parameters in the form of a POST request. Please guide me through it.
You should call your development machine from the device, by its ip address, based on how they are connected. Also you can use Android Reverse Tethering tools for your operating system. for further study and options you can take a look at the answers to this question
Related
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 am making call using the following callback method:
Callback<PeopleList> callback = new Callback<PeopleList>() {
#Override
public void onResponse(Response<PeopleList> response) {
Toast.makeText(LoginActivity.this,getString(R.string.login_failed), Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Throwable t) {
Toast.makeText(LoginActivity.this,getString(R.string.login_failed), Toast.LENGTH_SHORT).show();
}
};
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
retrofit.create(MyService.class).getPeopleData().enqueue(callback);
To the following interface:
public interface MyService {
#Headers("Accept: application/json")
#GET("/data/people/")
Call<PeopleList> getPeopleData();
}
This callback works just fine on successful requests. On unsuccessful ones however it does not give me the opportunity to investigate further as the onFailure method does not allow me to retrieve the http error code that came with the response.
On investigating further I found that according to several stackoverflow threads, the onResponse method should be called even on unsuccessful requests. This however seems to be at odds not only with my personal experience but also with the documentation of the Callback interface, which states that:
Communicates responses from a server or offline requests. One and only one method will be
invoked in response to a given request.
So the question is, how do I get the HTTP error code from a failed response if the onResponse method isn't called?
I think that the onResponse method gets called even if there is a response with an Error so something like this might work(sorry if I did something wrong first attempt to answer anybody :)
#Override
public void onResponse(Response<PeopleList> response) {
if(response.isSuccess()){ //good http request, do something with response.body()....
Toast.makeText(LoginActivity.this,getString(R.string.login_failed), Toast.LENGTH_SHORT).show();
} else { //bad http response do something with error message
try {
Toast.makeText(LoginActivity.this,response.errorBody().string().toString(), Toast.LENGTH_SHORT).show();
} catch (IOException e){
//IOException caught from response.errorBody().string() method
}
}
}
onResponse() will be always called, for failed requests .body() is null. response.isSuccess() is used to quickly distinguish requests with http codes between 200 and 300.
If you want to access http codes you can do the following:
int htppResultCode = response.raw().code();
It accesses the raw Response object which holds information about general outcome of the request.
I am developing a communication's system between an Android App and a Server.
I am using Retrofit API for the Android's communication with the Server.
When I do a GET (from Android side) to get info from the Server, I use a CallBackTask method like this:
public void testGet()
{
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(UserApi.SERVER)
.build();
final UserApi svc = restAdapter.create(UserApi.class);
if (svc != null) {
CallableTask.invoke(new Callable<Test>() {
#Override
public Test call() throws Exception {
Test g = svc.getTest();
System.out.println("getVdd() = "+g.getVdd()+"+ getResp() = "+g.getResp());
return g;
}
}, new TaskCallback<Test>() {
#Override
public void success(Test result) {
Intent i = new Intent(getApplicationContext(),SplashRapidoActivity.class);
startActivity(i);
}
#Override
public void error(Exception e) {
Toast.makeText(
getApplicationContext(),
"Unable to connect, please try again.",
Toast.LENGTH_SHORT).show();
}
});
}
}
Where the Test.class is a POJO class with variables and his getters and setters:
public class Test {
String vdd;
String resp;
public Test()
{
}
public void setVdd(String vdd) {
this.vdd = vdd;
}
public String getVdd() {
return vdd;
}
public void setResp(String resp)
{}
public String getResp()
{
return resp;
}
}
So, my question is, which is the best ERROR RESPONSE i could send from the server if there aren't valid values for the Test.class in the server?
Actually there is no "the best error response". It depends on your requirements. But there is widely used architecture called REST and Retrofit was designed in according with REST interaction. REST basically is just a set of rules which clients and servers understand without any documentation.
So if you want to retrieve(GET) some object/data from server by REST you can either receive it with status 200 or receive status 404 with appropriate description of error(or without it) inside body.
Here some more to read.
The best error response is one that make sense to you as a developer. I wouldn't mess with the default HTTP status/error codes. Instead I would send a specific response from the server. For example, keep the HTTP response code at 200 but in the data you send to the app set it to "ERROR: no values." or whatever you prefer. Then, in your Android app, check the response to see if it contains values or an error. Something like
if(resp.startsWith("ERROR:")){
// Do error handling //
} else {
// Normal code //
}
I'm using Retrofit library in my Android project. I have a rest server and trying to make request to it's login method. If login failed, server returns me 401 error and detailed message in json. My problem is that on my Nexus 5 with Android 5.0 it works fine, I can get the response body from the RetrofitError object. But on other devices, such as Sony Xperia M with Android 4.2.2 on the same request I'm getting No authentication challenges found exception and the RetrofitError.response object is null. Any ideas?
UPDATE
Here is my code. I also use Robospice library.
So this is an interface:
#POST("/auth")
User logIn(#Body UserSignUp userSignUp);
Here is my Robospice request class
public class UserLoginRequest extends RetrofitSpiceRequest<User, Server> {
private UserSignUp userSignUp;
public UserLoginRequest(UserSignUp userSignUp) {
super(User.class, Server.class);
this.userSignUp = userSignUp;
}
#Override
public User loadDataFromNetwork() throws Exception {
return getService().logIn(userSignUp);
}
}
And here is my request listener:
public final class UserLoginListener implements RequestListener<User> {
#Override
public void onRequestFailure(SpiceException spiceException) {
if (spiceException.getCause() != null && ((RetrofitError) spiceException.getCause()).getBody() != null) {
Toast.makeText(LoginActivity.this, ((ResponseDto) (((RetrofitError) spiceException.getCause()).getBody())).error, Toast.LENGTH_LONG).show(); //On Nexus 5 with Android 5 this line works fine
} else {
Toast.makeText(LoginActivity.this, "Login failed", Toast.LENGTH_SHORT).show(); //On other devices I'm getting to this
}
}
#Override
public void onRequestSuccess(User user) {
//Some code here
}
}
User is a subclass of ResponseDto class. ResponseDto class has only one public string field called error.
Seems that this exception is versions related - it's IOException thrown by HttpURLConnection. Try to change server's behavior or handle the IOException in retrofit.
No authentication challenges found
This error happens beause the server sends a 401 (Unauthorized) but does not give a WWW-Authenticate header which is a hint for the client what to do next.
Take a look here