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.
Related
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.
I have something like this
Retrofit retrofit =new retrofit2.Retrofit.Builder()
.baseUrl("URL")
.addConverterFactory(GsonConverterFactory.create())
.build();
requestService = retrofit.create(RequestInterface.class);
call = requestService.getData(page);
call.enqueue(new Callback<List<Cats>>() {
#Override
public void onResponse(Call<List<Cats>> call, Response<List<Cats>> response) {
....
}
#Override
public void onFailure(Call<List<Cats>> call, Throwable t) {
...
}
});
However when i want to get the second page, when i make a request for the second page within the same class, retrofit callback methods is not getting called.
call = requestService.getData(page); // page incremnted
call and requestService is globally defined
in Retrofit, each "call" instance is linked to one API call (single network request) and cannot be reused. You can reuse your RetrofitSerive instance, but for every new API call you will have to create a new Call object and enqueue it separately
You can use a generic response and use an url each time.
#GET
Call<Generic<T>> getUsers(#Url String url);
I want to POST JSON data having nested objects in it with the help of Asynctask in android studio, but I don't have good knowledge of API implementation in android studio. I am all new in android studio. I have successfully POST this data from POSTMAN, but I am not able to implement the code for it, also I don't have any tutorials for Asynctask. Please help me to implement code for this.
This is my Json data having nested Objects in it:
You don't need Async, Volley does it in the background for you. Put your JSONObject in the method instead of 'new JSONObject'. And YourURL - i.e '/api/route/'.
RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest request_json = new JsonObjectRequest(YourURL, new JSONObject(params)),
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
//Do what you want on response
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//If there's an error...
}
});
//Add process to queue to get JSON in background thread
queue.add(request_json);
Nowadays a better/simpler approach would be to use a libary like Retrofit to do all the magic for you.
You can simply send a Java instance model to an API endpoint. Retrofit takes care of converting it to json when using the GsonConverterFactory class and sends the json to the endpoint you provided with the given HTTP method.
Best and Simple Library for Implementation for API services by third party library made by Square, Retrofit a Easy HTTP Client.
Why Retrofit? because, Retrofit automatically creates the background thread ,Parse the Json using GSON converter and get a call success and Failure call back directly on main thread. Without writing too much boiler plate code of AsyncTask and Parsing JSON and getting the result on main thread.
Make Retrofit Client.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
RetrofitInterface service = retrofit.create(RetrofitInterface.class);
Make Method in RetrofitInterface.
#POST("users/new")
Call<User> yourMethod(#Body UserType user);
Now Call your method and It will make your success and Failure Callback method
Call<List<Repo>> repos = service.yourMethod("octocat");
And then Call enque method to automatic create background thread.
repos.enqueue(new Callback<List<Repo>>() {
#Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
}
#Override
public void onFailure(Call<MainResponse> call, Throwable t) {
}
});
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 an android app that uses Android Async. I am using this library called Android Asynchronous Http Client
I made a method for a GET request
public String getVenues(String token) throws Exception {
AsyncHttpClient venuesReq = new AsyncHttpClient();
venuesReq.addHeader("Authorization", "Token token=" + token);
venuesReq.get(mainAct.httpRequestURL + "/venues", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String response) {
venues = response;
}
#Override
public void onFinish() {
// Completed the request (either success or failure)
}
return venues;
}
but when I call getVenues("token") the return is null, but when I try to call getVenues("token") after few seconds there are now results for venues.
I know that I am using async request so the venues doesn't return immediately.
Now what I want is, when I call getVenues("token") method there should be a returned response for the GET Request.
You need to use interface here take a look at this
https://stackoverflow.com/a/21773406/472336
Your class from where you are listening/asking for asyntask result need to impliment interface and call that interface method from asyntask..
Hope this helps