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!
Related
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 am using android as my front-end application and Spring boot as server part. I am using android retrofit library to connect with server.
When user logs onto server, he gets response like this.
So how do I extract "accessToken" and "tokenType" from body response?
Here is my login method in android:
private void login(LoginRequest loginRequest) {
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpClientBuilder.addInterceptor(logging);
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClientBuilder.build());
Retrofit retrofit = builder.build();
RestAPI client = retrofit.create(RestAPI.class);
Call<LoginRequest> call = client.signIn(loginRequest);
call.enqueue(new Callback<LoginRequest>() {
#Override
public void onResponse(Call<LoginRequest> call, Response<LoginRequest> response) {
if (response.code() == 200) {
Toast.makeText(getApplicationContext(), response.body().toString(),
Toast.LENGTH_LONG).show();
Intent i = new Intent(LoginActivity.this, PostsActivity.class);
//response.body should be somewhere here
startActivity(i);
}else{
Toast.makeText(getApplicationContext(), "Uneti podaci nisu dobri",
Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<LoginRequest> call, Throwable t) {
}
});
}
This is my LoginRequest class
public class LoginRequest {
private String username;
private String password;
public LoginRequest(String username, String password) {
this.username = username;
this.password = password;
}
}
Create model class for response like below
public class Token {
#SerializedName("tokenType")
private String tokenType;
#SerializedName("accessToken")
private String accessToken;
public String getTokenType() {
return tokenType;
}
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
}
Then change the Api return type to Call<Token>
Accordingly you also need to modify the call
call.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
if(response.isSuccessful()) {
Token token = response.body();
}
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
}
});
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.
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);