I use Retrofit to get data from RestApi to my application in Android.
I have a problem with Get method with parameter.
When I run my code I get RetrofitError: [...]: Only one HTTP method is allowed. Found: GET and GET.
myWebService:
#GET("/tag/{id}")
void getById(#Path("id") int id, Callback<Data> pResponse);
MainActivity:
String url = "xyz";
retrofit = new RestAdapter.Builder()
.setEndpoint(url)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
myWebService = retrofit.create(MyWebService.class);
myWebService.getById(id, new Callback<Data>() {
#Override
public void success(Data data, Response response) {
Log.d(CLASS_TAG, data.toString());
}
#Override
public void failure(RetrofitError error) {
}
});
For example: when i changed #GET("/tag/{id}") to #GET("/tag/1") everything works well.
Check you backend for Authorization filter :
you might have authorized the route /tag/but you also should authorize /tag/* to match the path with parameters syntax.
Please tell us about you backend so we can give you more inputs if needed.
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.
I am making an android app using Retrofit 2. My REST Api are all written in Liferay. Now in Liferay, what I have seen is, to access the web services we need to authenticate first. So i have authenticated like this
http://test:q1w2e3r4#192.168.0.110:8080/liferay-portlet/api/secure/jsonws/
Liferay has its own user authentication method which we have overridden.I checked the Web service call from Postman its working fine.
URL:http://test:q1w2e3r4#192.168.0.110:8080/liferay-portlet/api/secure/jsonws/customuserauthentication/authenticate-by-user-name
form-encoded values
companyId:10154
screenName:xyz
password:xyz
active:true
If i put this in the postman, it fetches the json response properly.
Now when i call the same from my android code i get a response "Unauthorized".
My Retrofit service
public interface LoginApi {
#FormUrlEncoded
#POST("/liferay-portlet/api/secure/jsonws/customuserauthentication/authenticate-by-user-name")
Call<User> login(#Field("companyId")long companyId,#Field("screenName")String screenName,#Field("password")String password,#Field("active")boolean active);
}
My RestApiManager Class(This class is used to call the service interface and create the retrofit builder)
public class RestApiManager {
private LoginApi loginApi;
public LoginApi login() {
if (loginApi==null) {
GsonBuilder gson=new GsonBuilder();
gson.registerTypeAdapter(String.class, new StringDeserializer());
Retrofit retrofit=new Retrofit.Builder()
.baseUrl("http://test:q1w2e3r4#192.168.0.110:8080")
.addConverterFactory(GsonConverterFactory.create())
.build();
loginApi=retrofit.create(LoginApi.class);
}
return loginApi;
}
A call to the RestApiManager
Call<User> callUser=restApiManager.login().login(loginData.getCompanyId(),loginData.getScreenName(),loginData.getPassword(),loginData.isActive());
callUser.enqueue(new Callback<User>() {
#Override
public void onResponse(Response<User> response, Retrofit retrofit) {
Log.d("Login","Login Response:"+response.body());
}
#Override
public void onFailure(Throwable t) {
Log.d("Login","Login Response:"+t.getMessage());
}
});
It looks like perhaps your request should have a JSON body instead of a POST variables? You are calling a JSON webservice and your example parameters look more JSON than POST. If so, then you can encapsulate your parameters in an object --
public class User {
int companyId;
String screenName;
String password;
boolean active;
User(int companyId, String screenName, String password, boolean active) {
this.companyId = companyId;
this.screenName = screenName;
this.password = password;
this.active = active;
}
Your interface would be --
public interface LoginApi {
#POST("/liferay-portlet/api/secure/jsonws/customuserauthentication/authenticate-by-user-name")
Call<User> login(#Body User user);
}
and construct your call as --
User user = new User(loginData.getCompanyId(),loginData.getScreenName(),loginData.getPassword(),loginData.isActive());
Call<User> callUser = restApiManager.login().login(user);
The session management in cross-platform does not work the way it works on browser. Postman is a web client that works on browser platform.
1.One solution is to maintain cookies on the device.
Check this answer manage sessions with Android Application.
2.The other solution would be to use Json Web Token based auth.
I tried to run your demo code in my local PC, but no lucky as your server is in your local area network, about this question if you are using cookie or session authorize in you server side, I would suggestion you try to setCookieHandler as following, the PersistentCookieStore.java you can find here
private PersistentCookieStore cookieStore= new PersistentCookieStore(JApplication.getInstance().getApplicationContext());
CookieManager cookieManager = (new CookieManager(
cookieStore,
CookiePolicy.ACCEPT_ALL));
okHttpClient.setCookieHandler(cookieManager);
OkClient okClient = new OkClient(okHttpClient);
RestAdapter restAdapter = new RestAdapter.Builder()
.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader(Constant.Header_UserAgent, getUserAgent());
}
})
.setClient(okClient)
.setEndpoint(URL)
.setErrorHandler(new HttpErrorHandler())
.setConverter(new GsonConverter(gson))
.build();
It may be difficult to us to help you without knowing exactly which request your Retrofit Api is building.
So I recommend you to configure a Logging Interceptor to get in touch with what is really happening then if you still don't know what is going on you could come back to us with more information.
Check this answer to discover how to configure LoggingInterceptor with Retrofit 2:
Logging with Retrofit 2
Hope that it helps.
Best regards.
I tried all the solutions given here, but unfortunately nothing worked.The only solution i found to call the lifer service from within android is to use lifer mobile sdk.It already has methods and services to call liferay services. You can also call upon your custom services.More info
Liferay Mobile SDK
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 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
I have some problems using retrofit as my web communication interface against a php webservice contained in a worpress website - upon a call for one of the JSON API methods in the WP site I get an SSL exception on my android client even though I run over http and not https.
Here is my code -
public class RestApi {
private static final String API_URL = "https://tmc.co.nf/api";
private SmokeTalkRest service;
interface SmokeTalkRest {
#FormUrlEncoded
#POST("/get_nonce")
void getNonce(#Field("controller") String controller, #Field("method") String method, Callback<String> callback);
}
public RestApi() {
// Create a very simple REST adapter which points the GitHub API
// endpoint.
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer(API_URL).build();
// Create an instance of our GitHub API interface.
service = restAdapter.create(SmokeTalkRest.class);
}
public void getNonceForMethod(Method method, Callback<String> callback) {
service.getNonce("user", method.name(), callback);
}
}
The get nonce is called upon a button click, did someone already bumped into that?
I believe the issue you are having is your trying to call retrofit but not using the async version. The callback is probably the easiest to use.
#GET("/user/{id}")
void listUser(#Path("id") int id, Callback<User> cb);
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer("baseURL")
.build();
ClientInterface service = restAdapter.create(ClientInterface.class);
Callback callback = new Callback() {
#Override
public void success(Object o, Response response) {
//do something
}
#Override
public void failure(RetrofitError retrofitError) {
}
};
service.listUser(1, callback);
How to implement an async Callback using Square's Retrofit networking library
Android now requires you to do any webrequests async otherwise it will error out.
Also, retorfit will convert/parse the object for you so you dont have to. It saves time when it comes to creating async tasks and setting up the parsing. It also give a nice standard to go by when doing requests as well.