I'm novice on using Retrofit, I want to post data as an json data with object format to server and get response from that, I tested my restful url with fake data and that work fine without any problem, but when i post data from android i get null. what i want to do? i want to post data to server and get response with this format:
public class UserLoginInformation {
private String username;
private String userUniqueId;
}
My interface:
public interface SignalRetrofitServiceProviders {
#POST("joinUserToApplication")
Call<List<UserLoginInformation>> joinUserToApplication(#Body Object data);
}
post data:
private void joinUserToApplication(String data) {
AlachiqRestFullProvider signalProvider = new AlachiqRestFullProvider();
SignalRetrofitServiceProviders signalRetrofitServiceProviders = signalProvider.getServices();
Call<List<UserLoginInformation>> call = signalRetrofitServiceProviders.joinUserToApplication(data);
call.enqueue(new Callback<List<UserLoginInformation>>() {
#Override
public void onResponse(Call<List<UserLoginInformation>> call, Response<List<UserLoginInformation>> response) {
List<UserLoginInformation> result = response.body();
final String r = new Gson().toJson(result);
}
#Override
public void onFailure(Call<List<UserLoginInformation>> call, Throwable t) {
t.printStackTrace();
Log.e("onFailure ", t.getMessage());
}
});
}
RestFull provider:
public class AlachiqRestFullProvider {
private SignalRetrofitServiceProviders signalRetrofitServiceProviders;
public AlachiqRestFullProvider() {
OkHttpClient httpClient = new OkHttpClient();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ClientSettings.ALACHIQ_WEB_BASE_URL)
.client(httpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
signalRetrofitServiceProviders = retrofit.create(SignalRetrofitServiceProviders.class);
}
public SignalRetrofitServiceProviders getServices() {
return signalRetrofitServiceProviders;
}
}
data for post:
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("mobileNumber", mobileNumber);
jsonObject.put("userUniqueId", uuid);
jsonObject.put("userPhoneNumbers", phoneContacts);
startService(
new Intent(context, AlachiqRestFullWebServiceProvider.class)
.putExtra("request_type", "joinUserToApplication")
.putExtra("data", jsonObject.toString()));
} catch (JSONException e) {
e.printStackTrace();
}
server response data like with this format:
{"username":"mahdi","userUniqueId":"fwcrwcrwr23234c24"}
server side application to get data is:
Route.post('joinUserToApplication', function *(request, response) {
console.log(request._raw);
response.send({username: "mahdi", userUniqueId: "fwcrwcrwr23234c24"});
});
The POST body that is being serialized is a generic Object.
Create a POJO with the fields that you require and use a deserializer that retrofit understands
public interface SignalRetrofitServiceProviders {
#POST("joinUserToApplication")
Call<List<UserLoginInformation>> joinUserToApplication(#Body UserLoginInformation data);
}
Please note the parameter of the function is not changed to UserLoginInformation
http://square.github.io/retrofit/#restadapter-configuration
Related
I am using Twilio Rest API for sending wireless commands using the android studio.
I have implemented the code structure according to their documentation for wireless commands. but when I hit the button to get the response, instead of getting the desired result I am getting Unauthorized 401 response. I am using their API for the first time, so clearly not having an idea, what I am doing wrong here.
Here is my code for this:
public void byApi() {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ApiRetro.BASE_URL)
.build();
here SIMSID is the unique anme for the twilio sim card and the command i am sending is hello machine!
Credentials credentials=new Credentials(SIMSID,COMMAND);
ApiRetro apiRetro = retrofit.create(ApiRetro.class);
Call<ResponseBody> call = apiRetro.getSid(credentials);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response.isSuccessful())
{
try {
String hyyy=response.body().string();
try {
JSONObject jsonObject=new JSONObject(hyyy);
String test=jsonObject.getString("status");
Log.v("sdfg",test);
} catch (JSONException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
Log.v("TAG",response.body().string());
Toast.makeText(getApplicationContext(),response.body().string(),Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
}
else
{
Toast.makeText(getApplicationContext(),response.code()+" "+response.message(),Toast.LENGTH_LONG).show();
Log.v("one", String.valueOf(response.errorBody()));
Log.v("two",response.message());
Log.v("three", String.valueOf(response.code()));
Log.v("four", String.valueOf(response.headers()));
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
t.getStackTrace();
}
});
}
The interface for the Retrofit request looks like this:
String BASE_URL = "https://wireless.twilio.com/v1/";
#Headers({"AccountSid:yyyyyyyyyyyyyyyyyxxxx",
"AuthToken: yyyyyyyyyyyyyyyyyyyyxxx",
"token: ",
"Content-Type: application/x-www-form-urlencoded"})
#POST("Commands")
Call<ResponseBody> getSid(#Body Credentials credentials);
Body class:
public class Credentials {
String Sim;
String Command;
public Credentials(String sim, String command) {
Sim = sim;
Command = command;
}
public String getSim() {
return Sim;
}
public void setSim(String sim) {
Sim = sim;
}
public String getCommand() {
return Command;
}
public void setCommand(String command) {
Command = command;
}
}
OK ,i solved it .The issue was in the request where i was not sending according to the requirements.
by adding interceptor solved my problem
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new BasicInterceptor(SID,AUTH))
.build();
and then just
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.baseUrl(ApiRetro.BASE_URL)
.build();
and removing the headers from the interface like
#POST("Commands")
#FormUrlEncoded
Call<ResponseBody> getSid(#Field("Sim") String sim,#Field("Command") String command);
I have a Restful API whos return a Java Object for me. When return that object it is still empty, because the async thread is still working. How can get that response and return then to my Presenter and it directs the correct response to the view?
That is my retrofit call:
public String checkUser(final ModelUser modelUser) throws IOException {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(UserRetrofitAPI.BASE_SERVICE)
.addConverterFactory(GsonConverterFactory.create())
.build();
UserRetrofitAPI userRetrofitAPI = retrofit.create(UserRetrofitAPI.class);
Call<ModelUser> requestCheckUser = userRetrofitAPI.checkUser(modelUser.getUser(), modelUser.getPassword());
requestCheckUser.enqueue(new Callback<ModelUser>() {
#Override
public void onResponse(Call<ModelUser> call, retrofit2.Response<ModelUser> response) {
if(!response.isSuccessful()){
myModelUser = new ModelUser(modelUser.getUser(),modelUser.getPassword(), String.valueOf(response.code()));
} else {
ModelUser modelUserChecked = response.body();
myModelUser = modelUserChecked;
}
}
#Override
public void onFailure(Call<ModelUser> call, Throwable t) {
Exception ex = new Exception(t);
myModelUser = new ModelUser(modelUser.getUser(), modelUser.getPassword(), ex.toString());
}
});
return myModelUser.getResponse();
}
when I do this debugging, it works, by processing time.
help me?
You shouldn't return that directly.
As you mentioned Retrofit response is updated in background thread.
I would suggest to return requestCheckUser only and observe that in your Presenter
public Call<ModelUser> checkUser(final ModelUser modelUser) throws IOException {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(UserRetrofitAPI.BASE_SERVICE)
.addConverterFactory(GsonConverterFactory.create())
.build();
UserRetrofitAPI userRetrofitAPI = retrofit.create(UserRetrofitAPI.class);
Call<ModelUser> requestCheckUser = userRetrofitAPI.checkUser(modelUser.getUser(), modelUser.getPassword());
return requestCheckUser;
}
Observe response of that call in Presenter and perform required operations as follows
checkUser(modelUser).enqueue(new Callback<ModelUser>() {
#Override
public void onResponse(Call<ModelUser> call, retrofit2.Response<ModelUser> response) {
if(!response.isSuccessful()){
myModelUser = new ModelUser(modelUser.getUser(),modelUser.getPassword(), String.valueOf(response.code()));
} else {
ModelUser modelUserChecked = response.body();
myModelUser = modelUserChecked;
}
}
#Override
public void onFailure(Call<ModelUser> call, Throwable t) {
Exception ex = new Exception(t);
myModelUser = new ModelUser(modelUser.getUser(), modelUser.getPassword(), ex.toString());
}
});
This would be the simple option and will satisfy this use case and scope.
You can use custom Interface Listeners if you don't prefer to write observer in Presenter.
I would recommend to look into RxJava and use it with Retrofit to convert this into more maintainable code
I am currently developing android app which uses Retrofit & OkHttpClient to get/send data from the server.
That was great when calling my own server, while it runs into 404 error when trying to call google map api.
The following represents response with error.
Response{protocol=h2, code=404, message=, url=https://maps.googleapis.com/maps%2Fapi%2Fgeocode%2Fjson%3Fkey=defesdvmdkeidm&latlng=11.586215,104.893197}
This is obviously because '/' and '?' was encoded into "%2F" and "%3F".
The solution could be prevent urlencode for those special characters, but couldn't make it.
What I tried is add custom header "Content-Type:application/x-www-form-urlencoded; charset=utf-8" to OkHttpClient via intercepter but that does not work.
Best detailed response will be appreciated.
Regards.
private Retrofit createRetrofit(OkHttpClient client, String _baseUrl) {
return new Retrofit.Builder()
.baseUrl(_baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
}
private Retrofit createGoogleRetrofit() {
return createRetrofit(createGoogleClient(), baseUrl);
}
public DenningService getGoogleService() {
_baseUrl = "https://maps.googleapis.com/";
final Retrofit retrofit = createGoogleRetrofit();
return retrofit.create(DenningService.class);
}
public interface DenningService {
#GET("{url}")
#Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
Single getEncodedRequest(#Path("url") String url);
}
private void sendRequest(final CompositeCompletion completion, final ErrorHandler errorHandler) {
mCompositeDisposable.add(mSingle.
subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Function() {
#Override
public JsonElement apply(JsonElement jsonElement) throws Exception {
return jsonElement;
}
})
.subscribeWith(new DisposableSingleObserver() {
#Override
public void onSuccess(JsonElement jsonElement) {
completion.parseResponse(jsonElement);
}
#Override
public void onError(Throwable e) {
if (e instanceof HttpException && ((HttpException) e).code() == 410) {
errorHandler.handleError("Session expired. Please log in again.");
} else {
errorHandler.handleError(e.getMessage());
}
e.printStackTrace();
}
})
);
}
public void sendGoogleGet(String url, final CompositeCompletion completion) {
mSingle = getGoogleService().getEncodedRequest(url);
sendRequest(completion, new ErrorHandler() {
#Override
public void handleError(String error) {
ErrorUtils.showError(context, error);
}
});
}
The problem is in the definition of your Retrofit service interface and the values you pass to it.
public interface DenningService {
#GET("{url}")
#Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
Single getEncodedRequest(#Path("url") String url);
}
From what you've posted, I'm going to assume the value of url is:
maps/api/geocode/json?key=defesdvmdkeidm&latlng=11.586215,104.893197
Here's how it should look:
public interface DenningService {
#FormUrlEncoded
#GET("/maps/api/geocode/json")
Single getEncodedRequest(#Field("key") String key,
#Field("latlng") String latlng);
}
And then you'd call it like this:
mSingle = getGoogleService().getEncodedRequest(key, latlng);
Of course, you will have to figure out how to separate the key and latlng parameters out of the current url string.
Edit
It's not obvious to me whether or not you actually want your request to be application/x-www-form-urlencoded, or if you were just trying that to see if it solved your problem. If you do not want it, then your interface would look like this instead:
public interface DenningService {
#GET("/maps/api/geocode/json")
Single getEncodedRequest(#Query("key") String key,
#Query("latlng") String latlng);
}
I'm trying to shift over from volley to retrofit and I don't fully understand how to do a PUT with a JSONObject that contains a JSONArray.
The JSONObject body that I want to send to the server should look like this:
{
“account”: [
{“availability”: “offline”}
]}
here is my pojo
public class AvailabilityModel {
JSONObject account;
public AvailabilityModel(JSONObject account) {
this.account = account;
}
}
and my interface
public interface AvailabilityAPI {
#Headers( "Content-Type: application/json" )
#PUT(PATH)
Call<AccountParentModel> setAvailability(#Path("parameter") String accountId, #Body AvailabilityModel object);
class Factory {
private static AvailabilityAPI service;
public static AvailabilityAPI getInstance() {
if (service == null) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(App.BASE_URL)
.build();
return service = retrofit.create(AvailabilityAPI.class);
} else {
return service;
}
}
}
}
and finally, In my activity I do this:
JSONObject account = new JSONObject();
JSONArray array = new JSONArray();
JSONObject obj = new JSONObject();
try {
obj.put("availability", "offline");
} catch (JSONException e) {
e.printStackTrace();
}
array.put(obj);
try {
cloudNumber.put("account", array);
} catch (JSONException e) {
e.printStackTrace();
}
Log.e(this.getClass().getSimpleName(), "JSONObj sent to the server is: " + account);
AvailabilityModel availabilityModel = new AvailabilityModel(account);
AvailabilityAPI.Factory.getInstance().setAvailability(accountId, availabilityModel).enqueue(new Callback<AccountParentModel>() {
#Override
public void onResponse(Call<CloudNumberParentModel> call, Response<CloudNumberParentModel> response) {
Log.e("HomeActivity", "Success: availability = " + response.body().cloudNumbers.get(0).getAvailability());
}
#Override
public void onFailure(Call<CloudNumberParentModel> call, Throwable t) {
Log.e(this.getClass().getSimpleName(), " No good bro " + t.getMessage());
}
});
the problem with this is the server receives it in this format:
{“nameValuePairs”:{“account”:{“values”:[{“nameValuePairs”:{“availability”:“available”}}]}}}
Any help will be much appreciated.
Dont do like that..
let me give some brief to simply understand you about that.
step 1. take your json reqest .
In your case
{ “account”: [ {“availability”: “offline”} ]}
Step 2 . make model class.
That i describe at here Link
So in your case your model class is.
public class AvailabilityModel {
private List<AccountBean> account;
public List<AccountBean> getAccount() {
return account;
}
public void setAccount(List<AccountBean> account) {
this.account = account;
}
public static class AccountBean {
/**
* availability : offline
*/
private String availability;
public String getAvailability() {
return availability;
}
public void setAvailability(String availability) {
this.availability = availability;
}
}
}
Step 3 : putting value inside model class
first
AccountBean account = new AccountBean();
account.setAvailability("offline");
now take one array
List<AccountBean>list = new List<AccountBean>();
list.add(account);
so above is your list of account. now one step to complete make model.
AvailabilityModel model =new AvailabilityModel();
model. setAccount(list);
Happy coding :)
There's something about Retrofit that I'm not getting. I'm following examples on the web, but can't get it to even compile. I am able to access the data from the RESTful service via old school (i.e. HttpGet/HttpResoponse) so I know the service works. It returns a bunch of EmployeeData (as oppose to just one EmployeeData)
In the app gradle file:
dependencies {
...
compile 'com.google.code.gson:gson:2.7'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
...
}
The url for the RESTful service endpoint is:
https://com.somewhere/PhoneDirectoryService/api/Employees/
I have defined a string for the base url:
<string name="https_phone_directory_service_baseurl">https://com.somewherePhoneDirectoryService/api/</string>
Interface
public interface EmployeesService {
#GET("Employees.json") // the string in the GET is end part of the endpoint url
public Call<List<EmployeeEndpointResponse>> listEmployees();
}
Response
public class EmployeeEndpointResponse {
private List<EmployeeData> employees; // EmployeeData is a POJO
// public constructor is necessary for collections
public EmployeeEndpointResponse() {
employees = new ArrayList<EmployeeData>();
}
public static EmployeeEndpointResponse parseJSON(String response) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
Type collectionType = new TypeToken<List<EmployeeData>>(){}.getType();
Gson gson = gsonBuilder.create();
EmployeeEndpointResponse employeeEndpointResponse = gson.fromJson(response, EmployeeEndpointResponse.class);
return employeeEndpointResponse;
}
}
Get the data
public static boolean getEmployeeData(Context context) {
Resources resources = context.getResources();
URI uri = null;
try {
uri = new URI(resources.getString(R.string.https_phone_directory_service_baseurl));
}
catch (URISyntaxException exception) {
Log.e("getEmployeeData", exception.toString());
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(uri.toString())
.addConverterFactory(GsonConverterFactory.create())
.build();
Call<List<EmployeeEndpointResponse>> call = service.listEmployees();
EmployeesService service = retrofit.create(EmployeesService.class);
// this does not compile
// error: <anonymous com.somewhere.utilities.Utilities$1> is not
// abstract and does not override abstract method
// onFailure(Call<List<EmployeeEndpointResponse>>,Throwable) in Callback
call.enqueue(new Callback<List<EmployeeEndpointResponse>>() {
#Override
public void onResponse(Response<List<EmployeeEndpointResponse>> response) {
List<EmployeeEndpointResponse> myList = response.body();
// Successfull request, do something with the retrieved messages
}
#Override
public void onFailure(Throwable t) {
// Failed request.
}
});
// so I tried this which gives compile error
// retrofit2.Callback<java.util.List
// <com.somewhere.gson.EmployeeEndpointResponse>>)
// in Call cannot be applied to anonymous retrofit2.Callback
// <com.somewhere.gson.EmployeeEndpointResponse>)
call.enqueue(new Callback<EmployeeEndpointResponse>() {
#Override
public void onResponse(Call<EmployeeEndpointResponse> call, Response<EmployeeEndpointResponse> response) {
// handle response here
EmployeeEndpointResponse employeeEndpointResponse = (EmployeeEndpointResponse)response.body();
}
#Override
public void onFailure(Call<EmployeeEndpointResponse> call, Throwable t) {
}
});
}
What do I need to do?
Data looks like:
[
{"Name":"Smith, Ken J.",
"Cell":"",
"EmailAddress":"Ken.Smith#somewhere.com",
"Location":"West",
"Phone":"555-555-5555",
"Address":"PO Box 555 5555 Del Norte",
"City":"Jackson",
"State":"WY",
"Zip":"85555",
"Latitude":42.24976,
"Longitude":-107.82171},
{"Name":"Cox, Daniel B.",
"Cell":"",
"EmailAddress":"daniel.cox#somewhere.com",
"Location":"West",
"Phone":"(555) 555-5516",
etc ...}
]
Add the dependency
dependencies {
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
}
Generate the http client
private static OkHttpClient getOkHttpClient(){
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.NONE);
OkHttpClient okClient = new OkHttpClient.Builder()
.addInterceptor(logging)
.build();
return okClient;
}
Getting the data
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(YOUR_URL)
.client(getOkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
EmployeesService service = retrofit.create(EmployeesService.class);
Call<EmployeeEndpointResponse> call = service.listEmployees();
call.enqueue(new Callback<EmployeeEndpointResponse>() {
#Override
public void onResponse(Call<EmployeeEndpointResponse> call, Response<EmployeeEndpointResponse> response) {
EmployeeEndpointResponse employeeEndpointResponse = response.body();
//manage your response
}
#Override
public void onFailure(Call<EmployeeEndpointResponse> call, Throwable t) {
}
});
Parsing JSON
Your POJO doesn't need any aditional methods to parse JSON. Just generate the code with GSON anotations with http://www.jsonschema2pojo.org/