Why response.body() its null? - android

Im using retrofit to send a a json object to the server, im trying to create a user, im sending this json object
{"apellido":"prueba","email":"prueba#hotmail.com","fechaDeNacimiento":"11/29/1998","formaDeRegistro":"Android","nombre":"prueba","password":"12345678","username":"prueba"}
In this example i create a invalid user , so the server response with a json object where code its the code error and message its the explication of the error
[{"code":"5","message":"The email is in use"}]
Interface
public interface UserClient {
#POST("usuarios")
Call<Usuarios> create(#Body Usuarios usuario);
}
Data model
import com.google.gson.annotations.SerializedName;
public class Usuarios {
#SerializedName("username")
String username;
#SerializedName("email")
String email;
#SerializedName("password")
String password;
#SerializedName("nombre")
String nombre;
#SerializedName("apellido")
String apellido;
#SerializedName("fechaDeNacimiento")
String fechaDeNacimiento;
#SerializedName("formaDeRegistro")
String formaDeRegistro;
String message;
public Usuarios(String email, String username, String password, String nombre, String apellido, String fechaDeNacimiento, String formaDeRegistro){
this.username=username;
this.email=email;
this.password=password;
this.nombre = nombre;
this.apellido= apellido;
this.fechaDeNacimiento = fechaDeNacimiento;
this.formaDeRegistro = formaDeRegistro;
}
public String getMessage(){
return message;
}
}
and Retrofit implement
OkHttpClient.Builder okhttpClientBuilder=new OkHttpClient.Builder();
HttpLoggingInterceptor loggin=new HttpLoggingInterceptor();
loggin.setLevel(HttpLoggingInterceptor.Level.BODY);
okhttpClientBuilder.addInterceptor(loggin);
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("https://intense-lake-39874.herokuapp.com")
.addConverterFactory(GsonConverterFactory.create())
.client(okhttpClientBuilder.build());
Retrofit retrofit = builder.build();
UserClient service = retrofit.create(UserClient.class);
Call<Usuarios> call = service.create(usuario);
call.enqueue(new Callback<Usuarios>() {
#Override
public void onResponse(Call<Usuarios> call, Response<Usuarios> response) {
Toast.makeText(Main2Activity.this,"Usuario Registrado! "+response.body().getMessage,Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<Usuarios> call, Throwable t) {
Toast.makeText(Main2Activity.this,"Algo fallo..",Toast.LENGTH_SHORT).show();
}
});
}
So i can see the logcat response but in the body its appoint to null, how i can acces to the "message"?
This is the logcat

That error is because your response is not successful therefore you need to parse the error body, try with this code:
if (response.isSuccessful()) {
// Do your success stuff...
} else
{
try
{
JSONObject jObjError = new JSONObject(response.errorBody().string());
Toast.makeText(getContext(), jObjError.getString("message"), Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
Of course that you can use another parser like Gson .

Related

Login with retrofit in android

I am trying to use login api via retrofit. I need to send only mobile number. When i am using postman body it is getting an output. but when iam calling with android its getting an error json like below
{
"error": "Validation error",
"error_code": "001",
"Validation_errors": {
"mobile": "<p>The Mobile field is required.</p>"
}
}
HomeActivity.class
ApiInterface apiService =
ApiClient.getClient().create(ApiInterface.class);
Map<String,String> user = new HashMap<>();
user.put("mobile",username.getText().toString().trim());
Call<ResponseBody> mService = apiService.loginwithno(user);
Log.d("TAG", "response: " + mService.toString());
mService.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
String result = response.body().string();
JSONObject mJsonObject = new JSONObject(result);
Log.d("TAG", "response: " + mJsonObject.toString());
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
buttonVisible();
username.setError("Please try again");
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
call.cancel();
buttonVisible();
Snackbar snackbar = Snackbar.make(buttonLogin,
"Please check your internet connection", Snackbar.LENGTH_LONG);
snackbar.show();
}
ApiClient
public class ApiClient {
public static final String BASE_URL = "http://nast.in/driverpool/api/index.php/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
}
ApiInterface
public interface ApiInterface {
#POST("account/login?")
Call<ResponseBody> loginwithno(#Body Map<String, String> mobile);
#POST("account/verifyotp")
Call<ResponseBody> verifyotp(#Body HashMap<String, String> mobile);//Param name: mobile, otp
#POST("account/resendotp")
Call<ResponseBody> resentotp(#Body HashMap<String, String> mobile);
}
Postman screenshot
First you don't need '?' in your api and i think you must send json in your #body so create class like this
public class SendLoginData{
#SerializedName("mobile")
public String mobile;
public SendLoginData(String mobile) {
this.mobile = mobile;
}
}
And use it in ApiInterface
#POST("account/login")
Call<ResponseBody> loginwithno(#Body SendLoginData post);
You need to make few changes in code.
Change your login api to receive json like this, include gson library if you have not added in project.
#POST("account/login?")
Call loginwithno(#Body Map mobile);
Create an ApiErrorResponse object to handle your api error. Add getter, setter and #SerializedName as required.
class ApiErrorResponse{
String error;
String error_code;
ValidationErrors Validation_errors;
}
class ValidationErrors{
String mobile;
}
on API error handle like this
if(!response.isSuccessful()){
Converter converter =
ApiClient.getClient().responseBodyConverter(ApiErrorResponse.class, new Annotation[0]);
ApiErrorResponse errors = null;
try {
errors = converter.convert(response.errorBody());
} catch (Exception e) {
}
if(errors!=null){
//Handle your API Error logic here
}
}

How to convert retrofit response into json object

I just wanted to know that how could I convert this retrofit library response which is actually a JSON response to JSON object so I could use this in my android app to do something because I can not do anything with response in the buffered reader.
public void getMe(){
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(ROOT_URL)
.build();
myApi api = adapter.create(myApi.class);
api.sendme(
userEmail,
rs,
Team1,
Team2,
new retrofit.Callback<retrofit.client.Response>() {
#Override
public void success(retrofit.client.Response result, retrofit.client.Response response) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(result.getBody().in()));
if (!output.equals("")) {
output = reader.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void failure(RetrofitError error) {
// loading.dismiss();
Toast.makeText(Leaderboard.this, "", Toast.LENGTH_LONG).show();
}
}
);
}
here get me is sending post response to the server
public interface myApi {
#FormUrlEncoded
#POST("/myleaderboard.php")
void sendme(
#Field("userEmail") String userEmail,
#Field("rs") String rs,
#Field("team1") String team1,
#Field("team2") String team2,
Callback<Response> callback);
}
I m getting JSON response and I have to store that in my android code somehow whether that be using JSON object or anything else if possible.
please help me with this
Just change the myAPi code to
public interface myApi {
#FormUrlEncoded
#POST("/myleaderboard.php")
void sendme(
#Field("userEmail") String userEmail,
#Field("rs") String rs,
#Field("team1") String team1,
#Field("team2") String team2,
Callback<JsonObject> callback);
}
it will return JsonObject directly
Use GsonConverterFactory to convert incoming json into model/pojo class
implementation 'com.squareup.retrofit2:converter-gson:LATEST_VERSION'
Please go through following links
Retrofit Library Tutorial
Consuming-APIs-with-Retrofit
Use this link to convert your JSON into POJO with select options as selected in image below [http://www.jsonschema2pojo.org/
You will get a POJO class for your response like this
public class Result {
#SerializedName("id")
#Expose
private Integer id;
/**
*
* #return
* The id
*/
public Integer getId() {
return id;
}
/**
*
* #param id
* The id
*/
public void setId(Integer id) {
this.id = id;
}
then and use interface like this:
#FormUrlEncoded
#POST("/api/level")
Call<Result> checkLevel(#Field("id") int id);
add the dependencies
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.+'
and call like this:
Call<Result> call = api.checkLevel(1);
call.enqueue(new Callback<Result>() {
#Override
public void onResponse(Call<Result> call, Response<Result> response) {
response.body(); // have your all data
int id =response.body().getId();
String userName = response.body().getUsername();
String level = response.body().getLevel();
}
#Override
public void onFailure(Call<Result> call, Throwable t) {
}
});
to get the response in JSON don't use addConverterFactory(GsonConverterFactory.create()) from Retrofit.

How to properly send a body in a request using android retrofit?

I'm not getting the same result I have in POSTMAN working with the Retrofit Android lib. Maybe I'm doing something wrong.
Below is my code that I use to call the API
#Override
protected Response doInBackground(Void... params) {
Response<UserModel> response;
try {
LoginModel loginModel = new LoginModel("password", mEmail, mPassword, "Mobile", "123#abc");
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
ServiceAPI serviceAPI = retrofit.create(ServiceAPI.class);
Call<UserModel> call = serviceAPI.getToken(loginModel);
try{
response = call.execute();
if (response.body() == null) {
Log.d(getString(R.string.app_name), response.errorBody().toString());
return response;
} else {
return response;
}
}catch ( IOException e){
Log.e(getString(R.string.app_name), e.getMessage());
}
Thread.sleep(2000);
} catch (InterruptedException e) {
return null;
}
return null;
}
Below the interface code
public interface ServiceAPI {
#POST("Token")
Call<UserModel> getToken(#Body LoginModel loginModel);
}
And the result is:
Class LoginModel.java
public class LoginModel {
#SerializedName("grant_type")
private String grantType;
private String username;
private String password;
#SerializedName("client_id")
private String clientId;
#SerializedName("client_secret")
private String clientSecret;
public LoginModel(String grantType, String username, String password, String clientId, String clientSecret) {
this.grantType = grantType;
this.username = username;
this.password = password;
this.clientId = clientId;
this.clientSecret = clientSecret;
}
}
With PostMan the result is different, getting the Token correction.
Update your api
#FormUrlEncoded
#Post("Token")
Call<UserModel> getToken(#Field("grant_type") String grantType),
#Field("username") String userName,
#Field("password") String password
// etc
);
And your api call
Call<UserModel> call = serviceAPI.getToken("password", mEmail, mPassword, ...);

Retrofit 2 - string error body is empty

Server returns JSON object in case of success and simple String for error case.
There are no problems with parsing JSON into object. The problem rises when I want to parse error since the response.errorBody().string() is empty.
When I send the same request using Postman the response as follows:
And I can't read this error... Anyone faced such problem?
Code code
gradle:
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.okhttp:okhttp:2.6.0'
RestClient.java:
private static GitApiInterface gitApiInterface;
...
public static GitApiInterface getClient() {
if (gitApiInterface == null) {
OkHttpClient okClient = new OkHttpClient();
okClient.interceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
return response;
}
});
Retrofit client = new Retrofit.Builder()
.baseUrl(URL_BASE)
.addConverterFactory(GsonConverterFactory.create())
.build();
gitApiInterface = client.create(GitApiInterface.class);
}
return gitApiInterface;
}
ApiInterface.java:
public interface ApiInterface {
#POST("/register/user/{email}/")
Call<User> postRegisterUser(#Path(value = "email", encoded = true) String email,
#Query("firstname") String firstName,
#Query("lastname") String lastName,
#Query("country") String country,
#Query("phone") String phone,
#Query("deviceid") String deviceId);
...
ServerRequests.java:
public void registerUser(#NonNull String email,
#NonNull String firstName,
#NonNull String lastName,
#NonNull String country,
#NonNull String phone,
#NonNull String deviceId,
#NonNull final RegisterUserCallback callback) {
showProgressBar();
RestClient.GitApiInterface service = RestClient.getClient();
Call<User> call = service.postRegisterUser(email, firstName, lastName, country, phone, deviceId);
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
hideProgressBar();
User user = response.body(); //this works great
if (response.isSuccess()) {
Log.d(TAG, "REGISTER success: " + response.message());
callback.onRegisteredUser(user);
} else {
try {
Log.e(TAG, "REGISTER fail: " + response.errorBody().string()); //empty error body
callback.onRegisterFailed(response.errorBody().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<User> call, Throwable t) {
hideProgressBar();
callback.onRegisterFailed("error");
}
});
}
My answer is based on HttpLoggingInterceptor class.
I wrote getStatusError() method by given in parameter response.errorBody().
private StatusError getStatusError(ResponseBody responseBody) {
StatusError statusError = null;
if (responseBody != null) {
try {
BufferedSource source = responseBody.source();
if (source != null) {
source.request(Long.MAX_VALUE); // Buffer the entire body.
Buffer buffer = source.buffer();
Charset charset = UTF8;
MediaType contentType = responseBody.contentType();
if (contentType != null) {
charset = contentType.charset(UTF8);
}
String string = buffer.clone().readString(charset);
if (!TextUtils.isEmpty(string)) {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
statusError = gson.fromJson(string, StatusError.class);
}
}
} catch (Exception e) {
LogUtils.LOGW(TAG, "Impossible to get StatusError stream", e);
}
}
return statusError;
}
StatusError is a POJO class to map (JSON) elements:
public class StatusError {
#SerializedName("message")
public String message;
#SerializedName("errors")
public ArrayList<ErrorDetail> errors;
}

Simple login form with Retrofit

I'm starting to work with Retrofit but I'm stuck on this simple step. I have a login form and I'm trying to authenticate with the server but I just can't send the request.
This is what I've tried:
My Retrofit client:
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
My login interface:
public interface Login {
#POST(LOGIN)
Call<String> loginWithCredentials(#Body LoginCredentials data);
}
The LoginCredentials class:
public class LoginCredentials {
private String name;
private String pass;
public LoginCredentials(String name, String pass) {
this.name = name;
this.pass = pass;
}
}
And the part where I call it:
#Override
public void onClick(View v) {
showProgress(true);
String username = userField.getText().toString();
String password = passField.getText().toString();
ApiController.Login loginClient = ApiController.createService(ApiController.Login.class);
Call<String> call =loginClient.loginWithCredentials(new LoginCredentials(username, password));
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
handleResponse(response.body());
}
#Override
public void onFailure(Call<String> call, Throwable t) {
showProgress(false);
Log.e(TAG, t.getLocalizedMessage());
}
});
}
And I keep getting the error Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $but I have no idea what it means.
I figured it out. It was easier than I thought. You can skip the parsing that Retrofit does by setting the response type of the method as ResponseBody. Them you just need to read the response and use the string() method that provides. That's it!
Example:
public interface Login {
#POST(LOGIN)
Call<ResponseBody> loginWithCredentials(#Body LoginCredentials data);
}
Then use like this:
String username = userField.getText().toString();
String password = passField.getText().toString();
ApiController.Login loginClient = ApiController.createService(ApiController.Login.class);
Call<ResponseBody> call = loginClient.loginWithCredentials(new LoginCredentials(username, password));
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
// get String from response
String stringResponse = response.body().string();
// Do whatever you want with the String
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
// handle error
}
});
This error means that gson trying to parse string from server as JSON object and can't find the opening bracket.
I think you could return actual JSON from server like
{"api_token": "token"}
Also this bug could possibly be solved by importing latest GSON version mentioned here

Categories

Resources