Retrofit:2.0.0-beta2 http call and response handling - retrofit

My backend returns this json object to signal a succesful new user registration
{
"error": false,
"message": "You have been successfully registered"
}
and this to signal the account already exists
{
"error": true,
"message": "Sorry, this email already exists"
}
and this on other registration failure
{
"error": true,
"message": "An error occurred!! Please try again"
}
I want to use retrofit:2.0.0-beta2 to make an asynchronous http call and handle the response to take the use to the home page or redirect to the login page accordingly.
Here's my POJO:
public class User {
public final String email, firstname, lastname, city, birthday, gender, password;
public User(final String email, final String firstname, final String lastname,
final String city, final String birthday, final String gender, final String password) {
this.email = email;
this.firstname = firstname;
this.lastname = lastname;
this.city = city;
this.birthday = birthday;
this.gender = gender;
this.password = password;
}
}
Here's my service:
public interface APIService {
#POST("/api/user")
Call<User> createUser(#Body User user);
}

You need to create a extra class to handled response.
public class ResponseApi{
public String error;
public String message;
}
You're inferface
#POST("/api/user")
Call<ResponseApi> createUser(#Body User user);

You need to implement onResponse listener and handle the redirects or any other action inside it.
For example:
protected void loginAttempt(final View v) {
authUser = new HashMap<>();
authUser.put("email", email.getText().toString());
authUser.put("password", password.getText().toString());
Call call = SubApplication.api.authUser(authUser);
call.enqueue(new Callback() {
#Override
public void onResponse(Call call, Response response) {
try {
JSONObject responseObject = new JSONObject(new Gson().toJson(response.body()));
Log.d("LoginActivity", "onResponse: " + responseObject.toString());
if (responseObject.getBoolean("success") == true) {
Toast.makeText(v.getContext(), getString(R.string.error_login_success), Toast.LENGTH_LONG).show();
Intent intent = new Intent(v.getContext(), DashboardActivity.class);
startActivity(intent);
finish();
} else {
Toast.makeText(v.getContext(), getString(R.string.error_login_failed), Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Log.e("LoginActivity", "Exception: " + e);
Toast.makeText(v.getContext(), getString(R.string.error_login_failed), Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call call, Throwable t) {
Log.e("LoginActivity", "onFailure: " + t);
}
});

Related

Adding a header in ActionFilterAttribute

I'm trying to assign a token to my header in the request and when the action has finished to save a new token. Problem is that it assigns it to the HttpContext.Request.Headers and not to the client that is calling the API.
ActionFilter
public class TokenFilter: ActionFilterAttribute {
private static string _token {
get;
set;
}
public override void OnActionExecuting(ActionExecutingContext filterContext) {
base.OnActionExecuting(filterContext);
if (_token != null) {
filterContext.HttpContext.Request.Headers.Add("AuthToken", "Token " + _token);
}
}
public override void OnActionExecuted(ActionExecutedContext filterContext) {
base.OnActionExecuted(filterContext);
_token = filterContext.HttpContext.Request.Headers["AuthToken"];
_token = _token.Substring(_token.IndexOf(" "));
_token = _token.Remove(0, 1);
if (Client.DefaultRequestHeaders.Contains("AuthToken"))
}
}
Controller Action
[HttpPost]
[TokenFilter]
public async Task < IActionResult > LogIn(User user) {
try {
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(
Encoding.UTF8.GetBytes(user.Username + ":" + user.Password)));
HttpResponseMessage clientTask = await client.GetAsync("https://localhost:44324/api/Auth/LogIn");
if (clientTask.IsSuccessStatusCode) {
string txtBlock = await clientTask.Content.ReadAsStringAsync();
var tokenObject = JsonConvert.DeserializeObject < SessionAPI > (txtBlock);
client.DefaultRequestHeaders.Authorization = null;
client.DefaultRequestHeaders.Add("AuthToken", "Token " + tokenObject.Token);
return RedirectToAction("Index", "Home");
}
else return View("LogInIndex", user);
}
catch(Exception e) {
throw new Exception("An Error has occured" + e);
}
}
The main idea is to have a token that after LogIn is to be assigned to every request that is sent to the API untill Log Out. I know that i can use cookies but part of the assignment is not to use them. Currently i have the Token just being a static string for testing, but that eventually has to be moved somewhere dynamicly for every User.
EDIT
This is an example method that can be called after a successful Log In
[HttpGet]
[TokenFilter]
public async Task<IActionResult> ListAll()
{
try
{
//client.DefaultRequestHeaders.Add("AuthToken", "Token " + HttpContext.Request.RouteValues["token"]);
HttpResponseMessage clientTask = await client.GetAsync("https://localhost:44324/api/User/ListAll");
if (clientTask.IsSuccessStatusCode)
{
string txtBlock = await clientTask.Content.ReadAsStringAsync();
List<User> users = JsonConvert.DeserializeObject<List<User>>(txtBlock);
client.DefaultRequestHeaders.Authorization = null;
return View("ListAll", users);
}
else
return RedirectToAction("Index", "Home");
}
catch (Exception e)
{
throw new Exception("An Error has occured" + e);
}
}
You don't have to override OnActionExecuting
You can do this as follow
public class TokenFilter: ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext filterContext)
{
if (_token != null)
{
filterContext.Response.Headers.Add("AuthToken", "Token " + _token);
}
}
}

Add image and other data through firebase auth

I want to store all the user info into firebase and pass the email and password to firebase auth and insert image to firebase, but here I get an error at taskSnapshot.getDownloadUrl().toString());
And I also not sure this is the correct way to pass user email and password to firebase auth or not
public void AddUser(final String UserEmail, final String Username, final String Password,
final String PhoneNumber, final String confirmPassword, final String Address) {
//first we encode the email into "," to enable check the firebase database
String email = UserEmail.replace(".", ",");
Userdatabase = FirebaseDatabase.getInstance().getReference("User").child(email);
Log.d("UserEmail", Userdatabase.toString());
Userdatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
String value = dataSnapshot.getValue(String.class);
Log.i(TAG, "UserEmail : " + value + " Had Already Exist");
Toasty.warning(getApplicationContext(), "The Email you use already Exist !", Toast.LENGTH_SHORT, true).show();
return;
}
if (!dataSnapshot.exists()) {
if (imageUri != null) {
StorageReference fileReference = storageReference.child(System.currentTimeMillis()
+ "." + getFileExtension(imageUri));
mUploadTask = fileReference.putFile(imageUri)
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
}
}, 500);
Toast.makeText(Signup.this, "Register successful", Toast.LENGTH_LONG).show();
final User user = new User(Address, confirmPassword, UserEmail, Password, PhoneNumber, Username,
taskSnapshot.getDownloadUrl().toString());
Userdatabase.setValue(user);
}
});
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
return;
}
});
firebaseAuth.createUserWithEmailAndPassword(UserEmail, Password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
progressDialog.dismiss();
if (!task.isSuccessful()) {
Log.i(TAG, "Buyer FirebaseAuth Register : Fail");
Toasty.error(getApplicationContext(), "The Email you use already Exist !", Toast.LENGTH_SHORT, true).show();
} else {
Log.i(TAG, "Buyer FirebaseAuth Register : Success");
UserEmail.replace(".", ",");
final User user = new User(Address, confirmPassword, UserEmail, Password, PhoneNumber, Username);
Userdatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (!dataSnapshot.exists()) {
Userdatabase.setValue(user);
Log.i(TAG, "FirebaseDatabase Add Buyer : Success");
Toasty.success(getApplicationContext(), "Register Complete", Toast.LENGTH_SHORT, true).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.w(TAG, "Database Error");
}
});
}
}
});
}
}
Here is the problem taskSnapshot.getDownloadUrl().toString()
The latest Firebase Library delivers the download url by calling the upload reference in an asychronous task
Here is the complete code
private String link;
mUploadTask = fileReference.putFile(imageUri)
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
fileReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri downloadUri) {
link = downloadUri.toString;
Toast.makeText(Signup.this, "Register successful", Toast.LENGTH_LONG).show();
final User user = new User(Address, confirmPassword, UserEmail, Password, PhoneNumber, Username,
link));
Userdatabase.setValue(user);
}
});
}
});

sqlite-net-extensions -- Create Table Async

My problem is that I'm using the CreateTableAsync method and is always returning "0". I researched and saw that this return is a mistake.
I wanted to know what I'm doing wrong.
Class Service Table:
public class SqliteTable
{
private readonly SqliteWrapper _sqliteWrapper;
public SqliteTable()
{
_sqliteWrapper = new SqliteWrapper();
}
private async Task<bool> CheckIfExistTable<T>() where T : new()
{
var connection = _sqliteWrapper.OpenDatabase();
try
{
var result = await connection.Table<T>().CountAsync();
return result.Equals(0);
}
catch (Exception e)
{
Logs.Logs.Error($"Error get count table {typeof(T).Name}: {e.Message}");
return false;
}
}
public async void CreateTable<T>() where T : new()
{
var connection = _sqliteWrapper.OpenDatabase();
if (await CheckIfExistTable<T>())
{
Logs.Logs.Info($"This table {typeof(T).Name} was created");
return;
}
var createTableResult = await connection.CreateTableAsync<T>();
var value = createTableResult.Results.Values.FirstOrDefault();
if (value.Equals(1))
{
Logs.Logs.Info($"Create table {typeof(T).Name}");
}
else
{
throw new Exception($"Error create table {typeof(T).Name}");
}
}
}
I create a Class Model Login. which would be the object to create the database.
public class Login
{
public Login()
{
}
public Login(string user, string password)
{
User = user;
Password = password;
}
public Login(int id, string user, string password)
{
Id = id;
User = user;
Password = password;
}
[PrimaryKey, AutoIncrement, Column("login_id")]
public int Id { get; set; }
[Unique, NotNull, Column("login_user")]
public string User { get; set; }
[NotNull, Column("login_password")] public string Password { get; set; }
}
I create Class CreateTableAsync. Which would be to intanciar the SqliteTable, to call the method CreateTable sending the object to create the database:
protected override void OnStart()
{
try
{
var sqliteTable = new SqliteTable();
sqliteTable.CreateTable<Login>();
}
catch (Exception e)
{
Logs.Logs.Error($"Error init application: {e.Message}");
}
}
Can someone help me?

How to return a Mono<ResponseEntity> where the response entity can be of two different types

I am new to Spring Webflux / Reactor Core and am trying to perform the following functionality:
call userservice.LoginWebApp()
If a user is returned, return ResponseEntity of type "User". If empty, Return ResponseEntity of type "String"
The following code gives a type error as .defaultIfEmpty() expects ResponseEntity of type user. Can you please advise on the correct operator / method to implement this functionality.
#PostMapping("api/user/login/webApp")
public Mono<ResponseEntity> login(#RequestBody Credentials credentials, ServerWebExchange serverWebExchange) {
return userService.loginWebApp(credentials, serverWebExchange)
.map(user -> ResponseEntity.status(HttpStatus.OK).body(user))
.defaultIfEmpty(ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid username or password"));
}
You can use the cast operator to downcast out of the generic, and I believe WebFlux will still be able to marshal the User and the String:
#PostMapping("api/user/login/webApp")
public Mono<ResponseEntity> login(#RequestBody Credentials credentials, ServerWebExchange serverWebExchange) {
return userService.loginWebApp(credentials, serverWebExchange)
.map(user -> ResponseEntity.status(HttpStatus.OK).body(user))
.cast(ResponseEntity.class)
.defaultIfEmpty(ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid username or password"));
}
I would do the following:
Make a base class for responses
abstract class Response {
}
Make separate classes for every kind of response (like UserResponse, ErrorResponse, NotFoundResponse etc) and extend them from the base Response class
class UserResponse extends Response {
private String login;
private String password;
public UserResponse(String login, String password) {
this.login = login;
this.password = password;
}
#JsonGetter("login")
public String getLogin() {
return login;
}
#JsonSetter("login")
public void setLogin(String login) {
this.login = login;
}
#JsonGetter("password")
public String getPassword() {
return password;
}
#JsonSetter("password")
public void setPassword(String password) {
this.password = password;
}
}
class ErrorResponse extends Response {
private String errorMessage;
public ErrorResponse(String errorMessage) {
this.errorMessage = errorMessage;
}
#JsonGetter("error_message")
public String getErrorMessage() {
return errorMessage;
}
#JsonSetter("error_message")
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
Explicitly set the type of return value Mono<ResponseEntity<Response>>
And that's it.
#GetMapping("/test/{login}")
public Mono<ResponseEntity<Response>> test(#PathVariable(value = "login") String login) {
return loginWebApp(login)
.map(userResponse -> ResponseEntity.status(HttpStatus.OK).body(userResponse))
.defaultIfEmpty(ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new ErrorResponse("bad login")));
}
Now let's try it with bad login:
And good login:
Full code can be found here

Volley body 400 error

I want to send a POST to a server with the body that is true or false. I have this code and I use the Volley library
ShoozyHeader() set Content type to text/plain and Accept to text/plain and other headers necessary for the authentication.
If I try on http://requestmaker.com/ and the server responds correctly but I run this code the server responds:
Bad Request - Invalid Header
HTTP Error 400. The request has an invalid header name.
If I remove the getBody() the server respond fine.
final String url = POSTS_URI + idPost + "/likes";
StringRequest strReq = new StringRequest(Request.Method.POST,
url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
Toast.makeText(act, "Network error", Toast.LENGTH_SHORT).show();
}
}
) {
#Override
public byte[] getBody() throws AuthFailureError {
return "true".getBytes();
}
};
Try this one, it worked fine for me:
JSONObject params = new JSONObject();
try {
params.put("likes", "true");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.POST,
url, params,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, response.toString());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
}
}) {
/**
* Passing some request headers
* */
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json; charset=utf-8");
return headers;
}
};
jsonObjReq.setRetryPolicy(new DefaultRetryPolicy(60000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
// Adding request to request queue
getRequestQueue(jsonObjReq);
Have you override getHeaders in your class that extends the Request ?
Here is how to:
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
Here is an example for seting up a Base64 (username, password) header:
#Override
private HashMap<String, String> getHeaders() {
HashMap<String, String> headers = new HashMap<>();
headers.put("Authorization", getAuthentication("usernameExample", "passwordExample"));
headers.put("Content-Type", "application/json; charset=utf-8");
Log.d(TAG + "");
return headers;
}
private String getAuthentication(String username, String password) {
String credentials = String.format("%s:%s", username, password);
String auth = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.DEFAULT);
return auth;
}

Resources