Here is my API end point:
http://192.168.1.22:8000/api/auth/login
I need to POST email and password to receive Token from server
Server Post response:
{
"status": "ok",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIsImlzcyI6Imh0dHA6XC9cL21vbmV5bWF0Y2guYXBwOjgwMDBcL2FwaVwvYXV0aFwvbG9naW4iLCJpYXQiOjE0OTE0OTYzNDEsImV4cCI6MTQ5MTQ5OTk0MSwibmJmIjoxNDkxNDk2MzQxLCJqdGkiOiJhZmJhMDEzMzI5OWIwZmY0MzY3MTdlZDE4NmVkODI4OSJ9.bGlInsHHjdveeabz0j_36yICZtK32q1B9oNW44dk_x4"
}
here is my service Retrofit 2:
public interface ApiInterface {
#POST("auth/login")
Call<Login> authenticate(#Body User user);
}
here is my Login Model
public class Login {
#SerializedName("status")
#Expose
private String status;
#SerializedName("token")
#Expose
private String token;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
here is my User Model:
public class User {
#SerializedName("email")
#Expose
private String email;
#SerializedName("password")
#Expose
private String password;
public User(String email, String password) {
this.email = email;
this.password = password;
}
}
and this is how i call it in Activity
public void sendNetworkRequest(User user){
Log.d(TAG,"send request fired");
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://192.168.1.22:8000/api/")
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
ApiInterface apiInterface = retrofit.create(ApiInterface.class);
Call<Login> call = apiInterface.authenticate(user);
call.enqueue(new Callback<Login>() {
#Override
public void onResponse(Call<Login> call, Response<Login> response) {
Toast.makeText(LoginActivity.this, "wuhuuu"+ response.body().getToken(), Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<Login> call, Throwable t) {
Log.d(TAG,"went wrong");
Toast.makeText(LoginActivity.this, "something went wront"+t.toString(), Toast.LENGTH_LONG).show();
}
});
}
UPDATED: this is the Error I get:
com.google.gson.stream.malformedjsonexception use jsonreader.setlenient(true) to accept malformed at line 1column 1 $path
UPDATE Note: the email and password need to be sent in body form data.
Note: I can access the API from browser in Emulator so i guess it means there is something wrong in my logic or approach.
Complete Stack trace:
D/LoginActivity: went wrong
com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $
at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1567)
at com.google.gson.stream.JsonReader.checkLenient(JsonReader.java:1416)
at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:597)
at com.google.gson.stream.JsonReader.peek(JsonReader.java:429)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:201)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25)
at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:116)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:211)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:106)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:133)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
To send form data using Retrofit 2.0
#Multipart
#POST("url")
Call<PlanResponse> authenticate(#Part("email") RequestBody eamilValue, #Part("password") RequestBody passwordValue);
use it like this:
String email = "email#mail.com";
String password = "password";
RequestBody emailValue = RequestBody.create(MediaType.parse("text/plain"), emailValue);
RequestBody passwordValue= RequestBody.create(MediaType.parse("text/plain"), passwordValue);
Call<Login> call = apiInterface.authenticate(emailValue,passwordValue);
Related
I have an Api for registering user to Database. I am using Retrofit2 library for consuming the Api.
The register api when I test it on postman returns perfect result but when I implement it in my android app, it give the error that email is not valid.
I have used all kind of email validations so that form is only submitted when email is valid. I can't understand the issue with this.
Here is my api for your reference:
**http://ec2-54-201-213-169.us-west-2.compute.amazonaws.com:9000/api/v1/auth/signup**
Here is my Retrofit Api:
#FormUrlEncoded
#POST("auth/signup")
Call<DefaultResponse> signup(
#Field("userId") String userId,
#Field("email") String email,
#Field("firstName") String firstName,
#Field("lastName") String lastName,
#Field("password") String password,
#Field("confirmPassword") String confirmPassword
);
Api has a built in check for validating email, It get triggered when I run my app even though email is Valid.
Here is the Java Implementation:
Call<DefaultResponse> call = RetrofitClient
.getInstance()
.getApi()
.signup(firstName, lastName, email, password, confirmPassword, userId);
call.enqueue(new Callback<DefaultResponse>() {
#Override
public void onResponse(Call<DefaultResponse> call, Response<DefaultResponse> response) {
DefaultResponse defaultResponse = response.body();
if (response.code() == 200) {
ViewUtils.showSuccessToast(RegisterActivity2.this, "Registered Successful");
} else if (response.code() == 201) {
ViewUtils.showErrorToast(RegisterActivity2.this, defaultResponse.getMsg());
}
loader.hide();
register_btn.setVisibility(View.VISIBLE);
}
#Override
public void onFailure(Call<DefaultResponse> call, Throwable t) {
showErrorToast(RegisterActivity2.this, t.getMessage());
loader.hide();
register_btn.setVisibility(View.VISIBLE);
}
});
My default response model:
public class DefaultResponse {
#SerializedName("error")
private boolean err;
#SerializedName("message")
private String msg;
public DefaultResponse(boolean err, String msg) {
this.err = err;
this.msg = msg;
}
public boolean isErr() {
return err;
}
public String getMsg() {
return msg;
}
}
here Api end point
signup(
#Field("userId") String userId,
#Field("email") String email,
#Field("firstName") String firstName,
#Field("lastName") String lastName,
#Field("password") String password,
#Field("confirmPassword") String confirmPassword
);
incorrect order of data passing. API end point expect second param as email but you are passing lastname
.signup(firstName, lastName, email, password, confirmPassword, userId);
try with correct order.
I'm using retrofit2 for password recovery, an API request is sent to the server with an email address which is entered by the user.
I'm only setting the email in the POJO ,and after the conversion, the JSON string looks like this:
{"email":"email#email.com", "password":"", "password_confirmation":"", "token":""}
But the JSON I need to send out, should look like this:
{"email":"email#email.com"}
If I'll create another POJO class with an email param then I'll get the required string, but I just want to know if it is possible, using the current POJO.
How would one convert a POJO object to a JSON string using gson for a specified field?
Please Refer to the below code:
public class User {
private String email;
private String password;
private String password_confirmation;
private String token;
public User() {
this.email="";
this.password="";
this.password_confirmation="";
this.token="";
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword_confirmation() {
return password_confirmation;
}
public void setPassword_confirmation(String password_confirmation) {
this.password_confirmation = password_confirmation;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
My Api interface
public interface Api{
#POST("/api/password/create")
#Headers({"Accept:application/json", "Content-Type:application/json"})
Call<User> Create(#Body RequestBody requestBody);
}
My Retrofit method
private void authenticateEmail(final Context context) {
User user=new User();
Api api=new Api();
String email = edt_forgot_email.getText().toString().trim();
Gson gson = new GsonBuilder()
.setDateFormat(SERVICE_DATE_FORMAT)
.setLenient()
.create();
api = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
user.setEmail(email);
Gson lGson = new GsonBuilder().setDateFormat(SERVICE_DATE_FORMAT).create();
String jsonString = lGson.toJson(user);
Log.d("debug", "jsonString==>" + jsonString);
final RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), jsonString);
Call<User> call = api.Create(requestBody);
Log.d("debug", "url: " + call.request().url().toString());
call.enqueue(new Callback<User>() {
#Override
public void onResponse(#NonNull Call<User> call, #NonNull Response<User> response) {
Log.d("debug", "responsecode==>" + response.code());
Log.d("debug", "responsebody==>" + response.body());
if (response.code() == 200) {
String msg = "We have emailed you OTP";
Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(#NonNull Call<User> call, #NonNull Throwable t) {
Toast.makeText(activity, "server error",Toast.LENGTH_SHORT).show();
}
});
}
Remove this code from constructor :
public User() {
this.email="";
this.password="";
this.password_confirmation="";
this.token="";
}
If you want to exclude empty values from output json, you should make it as null.
Good luck!
You can just create a JSON Object for the single field like this:
JSONObject data =new JSONObject();
data.put("email", email#email.com)
send data object to the retrofit.
I'm working with JSON response which I can get from my server, at the beginning I have to log in at my application so I use such api:
#Headers("Content-type: application/json")
#POST("/v1/login")
Call<Post> auth(#Body Post body);
and also my POJO-class:
public class Post {
#SerializedName("username")
private String username;
#SerializedName("password")
private String password;
public Post(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername (String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
and after all initialize it at my mainactivity class:
public void sendPost() {
final EditText titleEt = findViewById(R.id.login);
final EditText bodyEt = findViewById(R.id.password);
final String a = titleEt.getText().toString().trim();
final String b = bodyEt.getText().toString().trim();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://server/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
APIService mAPIService = retrofit.create(APIService.class);
//retrofit.create(APIService.class);
mAPIService.auth(new Post(a, b)).enqueue(new Callback<Post>() {
#Override
public void onResponse(#NonNull Call<Post> call, #NonNull Response<Post> response) {
if (response.isSuccessful()) {
Toast.makeText(LoginActivity.this, "Post submitted to API.", Toast.LENGTH_LONG).show();
Intent intent = new Intent(LoginActivity.this, SecondScreen.class);
findViewById(R.id.btn_submit).getBackground().setColorFilter(Color.parseColor("#1cd000"), PorterDuff.Mode.MULTIPLY);
startActivity(intent);
saveData();
/* try {
String responseString = String.valueOf(response.body());
TextView txt = findViewById(R.id.post);
txt.setText(responseString);
}
catch (Exception e){
e.printStackTrace();
}*/
} else {
Toast.makeText(LoginActivity.this, "Unable to submit post to API.Error!!!", Toast.LENGTH_LONG).show();
findViewById(R.id.btn_submit).getBackground().setColorFilter(Color.parseColor("#FF0000"), PorterDuff.Mode.MULTIPLY);
}
}
#Override
public void onFailure(#NonNull Call<Post> call, #NonNull Throwable t) {
Toast.makeText(LoginActivity.this, "Unable to submit post to API.", Toast.LENGTH_LONG).show();
}
});
}
as you can see I commented my trying to fetch some data from JSON response, in general, I would like to get my access token from the response and I also wouldn't like to create some classes for fetching if it is possible, because I have already initialized my retrofit at my MainActivity class. After logging in a can get my received and sent messages in JSON too, but I would like to insert this data into the simple listview. So I hope that somebody at this forum will help me with my problem. Sorry for my maybe bad English.
You have to understand that each Retrofit request is asynchronous, that means, it will eventually be executed while your application runs. You should use RxJava to help you with that, since you should use to observe the data you need to get from your API.
Important Note: Also updating UI in your response from retrofit might trigger exceptions due to not running in Main Thread.
Some useful links to implement what you need :
https://www.toptal.com/android/functional-reactive-android-rxjava
https://www.journaldev.com/20433/android-rxjava-retrofit
https://medium.com/3xplore/handling-api-calls-using-retrofit-2-and-rxjava-2-1871c891b6ae
i want to send string from app to server with retrofit 2, and get back return values. what is the problem?
but it doesn't work.
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
RatingApiService retrofitService=retrofit.create(RatingApiService.class);
Call<String> call = retrofitService.registration("saeed","ali");
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if(response!=null){
Log.i("upload","is success:" +response.body());
}else{
Log.i("upload","response is null");
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.i("upload","onFailure: "+t.getMessage());
}
});
Interface:
public interface RatingApiService {
#FormUrlEncoded
#POST("android/add2/{email}{password}")
Call<String> registration(#Path("email") String email, #Path("password") String password);
}
Instead of using parameters to pass your data; put it in a req.body, then send it. By doing so, you can bypass the URL string limit and the code is much more organized.
public interface RatingApiService {
#Headers("Content-Type: application/json") //Must be set to application/json so req.body can be read.
#POST("android")
Call<String> registration(#Body UserRegistrationRequest body);
}
Now, you might ask what is the " UserRegistrationRequest" class? that will be the object class that will be sent as a JSON object. We define it by:
public class UserRegistrationRequest {
final String email;
final String password;
UserRegistrationRequest(String email, String password){
this.email = email;
this.password = password;
}
}
And then the final step. This is how you convert the object to a JSON object and send it to your server.
UserRegistrationRequest userRegistrationRequest = new UserRegistrationRequest(
RegisterNameFragment.sFirstName, RegisterNameFragment.sLastName, RegisterEmailFragment.sEmail,
RegisterPasswordFragment.sPassword, RegisterAgeFragment.sAge);
Call<Void> call = retrofit.insertUserRegistration(userRegistrationRequest);
call.enqueue(new Callback<UserRegistration>() {
#Override
public void onResponse(Call<UserRegistration> call, Response<UserRegistration> response) {
Log.d("blue", "Data is sent");
}
#Override
public void onFailure(Call<UserRegistration> call, Throwable t) {
Log.d("blue", "fail");
}
});
You need to add #Body annotation to your method like below.
#POST("users/new")
Call<User> createUser(#Body User user);
The content of #Body is sent to server as request body.
If you want to send email and password to server, you should create object that contains such data and use the object in the #Body annotation.
I am new to Adroid developing. I have a login form which I have to post to server. I am using Retrofit 2 library. I get response code=400, message=Bad Request. What am i doing wrong?
Here is my interface:
public interface LoginService {
#POST("login")
Call<Login> createLogin(#Body Login login);
}
My Activity:
Login login = new Login(email, password);
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("https://xxxxxx.herokuapp.com/")
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
LoginService loginClient = retrofit.create(LoginService.class);
Call<Login> call = loginClient.createLogin(login);
call.enqueue(new Callback<Login>() {
#Override
public void onResponse(Call<Login> call, Response<Login> response) {
Log.d("response",response.toString());
}
#Override
public void onFailure(Call<Login> call, Throwable t) {
Toast.makeText(LoginActivity.this,":(",Toast.LENGTH_SHORT).show();
}
});
And my Login class:
public class Login {
private String email;
private String password;
public Login(String email, String password){
this.email = email;
this.password = password;
}
For login, app has to send json comprised like
{"email" : "x#y.z","password" : "abc",}
Thank you in advance!