I am accessing webservice API using retrofit2. The response from API is in JSON Format.
JSONResponseImage
In retrofit my client is making successful connection with API but I want to access "statusMessage": "Email Address already exists" which is sent by webservice. I have tried couple of things but no success.
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_SHORT).show();
} else {
switch(response.code()) {
case 409:
Log.e("TAG", "1: " +response.raw());
Toast.makeText(MainActivity.this, "email already Registered",
Toast.LENGTH_SHORT).show();
break;
}
}
}
seeImageLog
Add the following to your User class
private Integer statusCode;
private String statusMessage;
public Integer getStatusCode() {
return statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
public String getStatusMessage() {
return statusMessage;
}
public void setStatusMessage(String statusMessage) {
this.statusMessage = statusMessage;
}
Now you can access getStatusMessage() like response.body().getStatusMessage();
NOTE : setters are not necessary, adding getters will do the job
Use this code:
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
//This is the status message.
String statusMessage = response.body().getStatusMessage();
} else {
switch(response.code()){
case 409:
Log.e("TAG", "1: " +response.raw());
Toast.makeText(MainActivity.this, "email already Registered", Toast.LENGTH_SHORT).show();
break;
}
}
}
The User class:
public class User {
//No need to declare setStatusMessage as the value shall be set by retrofit automatically. No need to make this as public.
private String statusMessage;
public String getStatusMessage() {
//Return statusMessage declared in User class.
return statusMessage;
}
}
Related
i have setup retrofit client and the api interface, i have some code as follows
public Result<LoggedInUser> login(String username, String password) {
try {
apiInterface = ApiClient.getClient().create(ApiInterface.class);
RequestData requestData = new RequestData(username, password);
Call<RequestResponse> call = apiInterface.login(requestData);
call.enqueue(new Callback<RequestResponse>() {
#Override
public void onResponse(Call<RequestResponse> call, Response<RequestResponse> response) {
RequestResponse resource = response.body();
System.out.println(resource.getData().getAccessToken());
}
#Override
public void onFailure(Call<RequestResponse> call, Throwable t) {
call.cancel();
}
});
LoggedInUser fakeUser = new LoggedInUser(
java.util.UUID.randomUUID().toString(),
"Jane Doe");
return new Result.Success<>(fakeUser);
} catch (Exception e) {
return new Result.Error(new IOException("Error logging in", e));
}
}
I am not familar with the pattern that should be used to notify the repository class when the rest call obtains it's response.
the above code is called from the following code in the repository class
public Result<LoggedInUser> login(String username, String password) {
// handle login
Result<LoggedInUser> result = dataSource.login(username, password);
if (result instanceof Result.Success) {
setLoggedInUser(((Result.Success<LoggedInUser>) result).getData());
}
return result;
}
I've been building an app which has Log In functionality. I've tested it but every time i tried to Log In, the progress bar disappeared to quickly (like a quarter second or something), and the response i get from the server is like about 2 seconds after the progress bar disappeared. Here are some of my codes.
My LoginTask inner class :
private class LoginTask extends AsyncTask<Account, Void, Account>{
private String getUsername = username.getText().toString();
private String getPassword = password.getText().toString();
#Override
protected void onPreExecute() {
super.onPreExecute();
//showDialog();
progressBar.setVisibility(View.VISIBLE);
}
#Override
protected void onPostExecute(Account account) {
super.onPostExecute(account);
//dismissDialog();
progressBar.setVisibility(View.GONE);
}
#Override
protected Account doInBackground(Account... accounts) {
getLogin(getUsername, getPassword);
return null;
}
}
Login Retrofit call to server
private void getLogin(String email, String password) {
Call<LoginAuth> call = userService.getLogin(email, password);
call.enqueue(new Callback<LoginAuth>() {
#Override
public void onResponse(Call<LoginAuth> call, Response<LoginAuth> response) {
try {
if (response.body().getToken_type().equals("xxx")) {
Log.i(TAG, "getLogin, Authorized access");
Log.i(TAG, "getLogin, access_token: " + response.body().getAccess_token().toString());
Log.i(TAG, "getLogin, expires_at" + response.body().getExpires_at().toString());
} else {
Log.e(TAG, "getLogin, Unauthorized access" + response.body().getToken_type().toString());
}
} catch (Exception e) {
Log.e(TAG, "getLogin exception " + e.getMessage());
}
}
#Override
public void onFailure(Call<LoginAuth> call, Throwable t) {
Log.e(TAG, "getLogin, onFailure : " + t.getMessage());
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast.makeText(LoginActivity.this, "Unable to Log In :(", Toast.LENGTH_SHORT).show();
}
});
}
});
}
I want it to work like when the response is fetched, that's the time the progress bar disappeared (not instantly). Did i do something wrong with the code?
As you are using retrofit, there is no necessity to call your api in separate asynctask as retrofit manages it asynchronously. what you should do is show your progressbar before you call api and dismiss it in onResponse and onFailure both. so your code would change to something like below.
private void getLogin(String email, String password) {
progressBar.setVisibility(View.VISIBLE);
Call<LoginAuth> call = userService.getLogin(email, password);
call.enqueue(new Callback<LoginAuth>() {
#Override
public void onResponse(Call<LoginAuth> call, Response<LoginAuth> response) {
progressBar.setVisibility(View.Gone);
//rest of your code
}
#Override
public void onFailure(Call<LoginAuth> call, Throwable t) {
Log.e(TAG, "getLogin, onFailure : " + t.getMessage());
progressBar.setVisibility(View.Gone);
//rest of your code
}
});
}
I am able to do the initial log in to the server and get the token, but when I try to do another request I get the HTTP error 403, so I am not actually being authenticated.
When I go through the browser or the android application, this is the key that I am getting when I log in.
{
"key": "64ea43a78fa18da19364d2d0ae5a12371e5d0ee2"
}
Is there anything that I can do with this key using retrofit? I have tried using the header "Authorization" and following with the token.
Here is my RestClient interface:
public interface RestClient {
#POST ("rest-auth/login/")
Call<Token> login(
#Body Login body
);
#GET ("v2/users/{user}/")
Call<List<CustomUser>> getUser(
#Header("Authorization") String token,
#Path("user") String user
);
Here is the AsyncTask which will perform the requests to the server. The authenticateUser gives me an HTTP response of 200, but the syncUser gives 403.
public class ActionSync extends AsyncTask<String, Void, Boolean> {
RestClient client;
IData activity;
private static String token;
public ActionSync(Context context) {
activity = (IData) context;
}
#Override
protected Boolean doInBackground(String... params) {
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://" + params[2] + ":" + params[3] + "/")
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
client = retrofit.create(RestClient.class);
//Authenticate the user.
authenticateUser(params[0], params[1]);
//Once the authentication has been completed, we can now move on the syncing data.
syncUser(params[0]);
//If we get to the end without any errors, then return true. This means that the sync is complete.
return true;
}
#Override
protected void onPostExecute(Boolean loggedIn) {
super.onPostExecute(loggedIn);
}
public void authenticateUser(String username, String password){
//First, we must log into the server given our credentials. Otherwise, we will not be able to get any data.
Login login = new Login(username, password);
Call<Token> call = client.login(login);
call.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
if(response.isSuccessful()){
Log.v("ActionSync", "Login was successful");
token = response.body().getKey();
} else {
Log.v("ActionSync", "Login was unsuccessful");
}
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
Log.v("ActionSync", "Error occurred during login");
}
});
}
public void syncUser(String username){
Call<List<CustomUser>> call = client.getUser(token, username);
call.enqueue(new Callback<List<CustomUser>>() {
#Override
public void onResponse(Call<List<CustomUser>> call, Response<List<CustomUser>> response) {
Log.v("ActionSync", "The response from get user: " + response.toString());
}
#Override
public void onFailure(Call<List<CustomUser>> call, Throwable t) {
Log.v("ActionSync", "No response from get user");
}
});
}
public interface IData {
}
}
I know this is old or repeat question. But I didn't get where am I wrong.
I got result null from this JSON.
{
"error": {
"dateTimeUtc": "2017-12-26T05:46:05.1126801+00:00",
"errorReference": "sample string 2",
"errorType": "Error",
"title": "sample string 3",
"code": "sample string 4",
"messages": [
"sample string 1",
"sample string 2"
]
},
"result": {
"message": "sample string 1"
}
}
I have this type of JSON to read from Retrofit2.
I create one POJO class called RetrofitResponce
private Error error;
private Result result;
public Result getResult ()
{
return result;
}
public void setResult (Result result)
{
this.result = result;
}
public Error getError ()
{
return error;
}
public void setError (Error error)
{
this.error = error;
}
#Override
public String toString()
{
return "ClassPojo [result = "+result+", error = "+error+"]";
}`
Now in call.enque() method to handled response, like
call.enqueue(new Callback<RegisterUser>() {
#Override
public void onResponse(Call<RetrofitResponce> call, Response<RetrofitResponce> response) {
try {
RetrofitResponce retrofitResponce= response.body();
Error error = retrofitResponce.getError();
Result result=retrofitResponce.getResult();
Log.e("Eroor", "rr " + error.getTitle().toString());
} catch (Exception e) {
}
}
#Override
public void onFailure(Call<RetrofitResponce> call, Throwable t) {
Log.e("Failure ", "fail " + t.toString());
}
});
but here I get NullPointerException,i.e. I don't get any response in RestrofitResponce. Error and Result both get Null.
java.lang.NullPointerException: Attempt to invoke virtual method 'net.xyz.abc.Model.Error net.xyz.abc.Model.RegisterUser.getError()' on a null object reference
Please help me. try to solve my query.Thanks in advance.
PostMan responce,
{
"error": {
"dateTimeUtc": "2017-12-26T07:05:51.1427712Z",
"errorReference": "00000000-0000-0000-0000-000000000000",
"errorType": "Error",
"title": "The request is invalid.",
"code": null,
"messages": [
"Passwords must have at least one non letter or digit character. Passwords must have at least one uppercase ('A'-'Z')."
]
},
"result": null
}
Retrofit callback needs response model, just change this:
call.enqueue(new Callback<RetrofitResponce>() {
#Override
public void onResponse(Call<RetrofitResponce> call, Response<RetrofitResponce> response) {
if (response.isSuccessful()) {
RetrofitResponce retrofitResponce= response.body();
if (retrofitResponce!=null) {
Error error = retrofitResponce.getError();
Result result=retrofitResponce.getResult();
Log.e("Eroor", "rr " + error.getTitle().toString());
}
}
}
#Override
public void onFailure(Call<RetrofitResponce> call, Throwable t) {
Log.e("Failure ", "fail " + t.toString());
}
});
Happy coding!!
You have to add the #SerializedName in your Response class for each and every filed same as the web service name.
e.g
#SerializedName("error")
private Error error;
#SerializedName("result")
private Result result;
Please use this website to create your classes from the JSON Response.
http://www.jsonschema2pojo.org/
And after that you have to check if response if successful or not.
call.enqueue(new Callback<RegisterUser>() {
#Override
public void onResponse(Call<RetrofitResponce> call, Response<RetrofitResponce> response) {
try
{
if(response.isSuccessful() && response.body() != null)
{
RetrofitResponce retrofitResponce= response.body();
Error error = retrofitResponce.getError();
Result result=retrofitResponce.getResult();
}
} catch (Exception e) {
}
}
#Override
public void onFailure(Call<RetrofitResponce> call, Throwable t) {
Log.e("Failure ", "fail " + t.toString());
}
});
Try this Pojo for RetrofitResponce
public class RetrofitResponce {
#SerializedName("error")
#Expose
private Error error;
#SerializedName("result")
#Expose
private Result result;
public Error getError() {
return error;
}
public void setError(Error error) {
this.error = error;
}
public Result getResult() {
return result;
}
public void setResult(Result result) {
this.result = result;
}
}
public class Result {
#SerializedName("message")
#Expose
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
public class Error {
#SerializedName("dateTimeUtc")
#Expose
private String dateTimeUtc;
#SerializedName("errorReference")
#Expose
private String errorReference;
#SerializedName("errorType")
#Expose
private String errorType;
#SerializedName("title")
#Expose
private String title;
#SerializedName("code")
#Expose
private String code;
#SerializedName("messages")
#Expose
private List<String> messages = null;
public String getDateTimeUtc() {
return dateTimeUtc;
}
public void setDateTimeUtc(String dateTimeUtc) {
this.dateTimeUtc = dateTimeUtc;
}
public String getErrorReference() {
return errorReference;
}
public void setErrorReference(String errorReference) {
this.errorReference = errorReference;
}
public String getErrorType() {
return errorType;
}
public void setErrorType(String errorType) {
this.errorType = errorType;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public List<String> getMessages() {
return messages;
}
public void setMessages(List<String> messages) {
this.messages = messages;
}
}
Try this.
call.enqueue(new Callback<RetrofitResponce>() {
#Override
public void onResponse(Call<RetrofitResponce> call, Response<RetrofitResponce> response) {
if (response.body() != null)
Toast.makeText(YourActivity.this,response.body().getResult(),
Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<RetrofitResponce> call, Throwable t) {
Log.e("Failure ", "fail " + t.toString());
}
});
I am sure this will help you.
You can not handle Success and Faille by Single model.
To get error body you need to call response.errorBody().string()
Try Below Code :
call.enqueue(new Callback<RegisterUser>() {
#Override
public void onResponse(Call<RetrofitResponce> call, Response<RetrofitResponce> response) {
try {
if (response.isSuccessful()) {
Log.d("Successful",response.body(););
} else {
Log.d("errorBody ", response.errorBody().string());
}
} catch (Exception e) {
Log.d("Exception ",e.toString());
}
}
#Override
public void onFailure(Call<RetrofitResponce> call, Throwable t) {
Log.e("Failure ", "fail " + t.toString());
}
});
I am trying to implement a POST request via Retrofit, but the approach seems to be wrong, I guess. I followed the steps I used for GET request:
I defined the end point:
public interface GitHubEmailAPI {
#POST("/users/{user}")
Call<GitHubEmail> postEmail(#Field("email") String email);
}
The model:
public class GitHubEmail {
#SerializedName("email")
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
And the calling:
public void postEmail (){
GitHubEmailAPI apiService =
ApiClient.getClient().create(GitHubEmailAPI.class);
final Call<GitHubEmail> callEmail = apiService.postEmail
(String.valueOf(enterEmailEt.getText()));
callEmail.enqueue(new Callback<GitHubEmail>() {
#Override
public void onResponse(Call<GitHubEmail> call, Response<GitHubEmail> response) {
testTV.setText(callEmail.toString());
}
#Override
public void onFailure(Call<GitHubEmail> call, Throwable t) {
Log.e("Email", t.toString());
}
});
I am using the github api as a test, not sure if the access token needs to be included as a parameter in the request.
There are some info which you know about Retrofit ....
Your BASE_URL must be end with / .
When you using #Field notation you must put #FormUrlEncoded in Your Api call.
When you using {user} in the API method you have to use #Path("user") String user to relate to url data .
Your POST method URL will be like this #POST("users/{user}").
When your response Callback done the actual Data inside your Response<GitHubEmail> response in this variable. You have to use response.body() to get what you get response from API CALL.
Here is a sample code
#FormUrlEncoded
#POST("users/{user}")
Call<YourResultPojoClassHere> yourFuntionName(#Field("id") String id,#Path("user") String path);
please take look on below code ....
callEmail.enqueue(new Callback<GitHubEmail>() {
#Override
public void onResponse(Call<GitHubEmail> call, Response<GitHubEmail> response) {
if (response.isSuccessful()) {
if (response.body().getSuccess())
Toast.makeText(ClassName.this, response.body().getMessage(), Toast.LENGTH_SHORT).show();
else
Toast.makeText(ClassName.this, response.body().getMessage(), Toast.LENGTH_SHORT).show();
} else
Toast.makeText(ClassName.this, "Sorry for inconvince server is down", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<GitHubEmail> call, Throwable t) {
Toast.makeText(ClassName.this, "Check your Internet connection", Toast.LENGTH_SHORT).show();
}
}
});
For POST in retrofit you must include #FormUrlEncoded
#FormUrlEncoded
#POST("path_here")
Call<ResponseBody> function_name(#Field("data") String data);