0

I'm following a retrofit course in which I create a small backend with an api in which I have a POST method to perform a teacher's login. In the course what he does is create a teacher and with the set method he passes him the email and the password, which is what this method receives in the API.

I would like to do it in such a way that in the call to Retrofit you pass directly this email and password and I have done it in the following way:

public class LoginActivity extends AppCompatActivity {

    private EditText etPasswordLogin, etEmailLogin;
    private Button btLogin;
    private TextView tvSignUp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        setupView();
    }

    private void setupView() {

        etPasswordLogin = findViewById(R.id.loginEditTextPassword);
        etEmailLogin = findViewById(R.id.loginEditTextEmail);
        btLogin = findViewById(R.id.buttonSignUp);
        tvSignUp = findViewById(R.id.textViewSignUp);

        btLogin.setOnClickListener(v -> userSignUp());
        tvSignUp.setOnClickListener(v -> startActivity(new Intent(getApplicationContext(), SignUpActivity.class)));
    }

    private void userSignUp() {

        String email = etEmailLogin.getText().toString().trim();
        String password = etPasswordLogin.getText().toString().trim();

        if (email.isEmpty()) {

            etEmailLogin.setError(getResources().getString(R.string.email_error));
            etEmailLogin.requestFocus();
            return;
        }

        if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {

            etEmailLogin.setError(getResources().getString(R.string.email_doesnt_match));
            etEmailLogin.requestFocus();
            return;
        }

        if (password.isEmpty()) {

            etPasswordLogin.setError(getResources().getString(R.string.password_error));
            etPasswordLogin.requestFocus();
            return;
        }

        if (password.length() < 4) {

            etPasswordLogin.setError(getResources().getString(R.string.password_error_less_than));
            etPasswordLogin.requestFocus();
            return;
        }

        login(email, password);
    }

    private void login(String email, String password) {

        String BASE_URL = "http://10.0.2.2:8040";

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        WebServiceApi api = retrofit.create(WebServiceApi.class);
        Call<List<Profesor>> call = api.login(email, password);

        call.enqueue(new Callback<List<Profesor>>() {
            @Override
            public void onResponse(Call<List<Profesor>> call, Response<List<Profesor>> response) {
                if (response.code() == 200) {
                    Log.d("TAG1", "Profesor logeado");
                } else if (response.code() == 404) {
                    Log.d("TAG1", "Profesor no existe");
                } else {
                    Log.d("TAG1", "Error desconocido");
                }
            }

            @Override
            public void onFailure(Call<List<Profesor>> call, Throwable t) {
                Log.d("TAG Error: ", Objects.requireNonNull(t.getMessage()));
            }
        });

    }
}

And this would be my model teacher:

public class Profesor {

    @SerializedName("id")
    private Long id;
    @SerializedName("nombre")
    private String nombre;
    @SerializedName("email")
    private String email;
    @SerializedName("password")
    private String password;
    @SerializedName("foto")
    private String photo;

    public Profesor(){}

    public Profesor(Long id, String nombre, String email, String photo) {
        this.id = id;
        this.nombre = nombre;
        this.email = email;
        this.photo = photo;
    }

    public Profesor(String email, String password){
        this.email = email;
        this.password = password;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    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 getPhoto() {
        return photo;
    }

    public void setPhoto(String photo) {
        this.photo = photo;
    }
}

Finally the call to Retrofit that I make is the following:

@FormUrlEncoded
@POST("api/login")
Call<List<Profesor>> login(@Field("email") String email, @Field("password") String password);

However when I run the application and pass through the form the email and password, in the log I return "Error desconocido", however in postman gives me answer without problems:

postman image

Any idea what I'm doing wrong?

Ludiras
  • 338
  • 3
  • 20

1 Answers1

1

Your postman request is not a form-urlencoded, but raw. You need to send a json as a request, and not a field. So to fix this, you may change your API, to handle form-urlencoded requests, or change the Android code this way.

public class LoginCredentials {
    @SerializedName("email")
    private String email;
    @SerializedName("password")
    private String password;

    public LoginCredentials(String email, String password) {
        this.email = email;
        this.password = password;
    }
}

and change this

@FormUrlEncoded
@POST("api/login")
Call<List<Profesor>> login(@Field("email") String email, @Field("password") String password);

to this

@POST("api/login")
Call<List<Profesor>> login(@Body LoginCredentials credentials);

Hope this will help.

Aram
  • 695
  • 1
  • 5
  • 20
  • So the problem with me not being able to pass the request that way is that the API I'm using isn't configured for it? – Ludiras Dec 15 '19 at 20:19
  • exactly, you can read this question for more details https://stackoverflow.com/questions/26723467/what-is-the-difference-between-form-data-x-www-form-urlencoded-and-raw-in-the-p – Aram Dec 15 '19 at 20:22
  • Mmmm okay, and what would be the difference between creating a new model class with the fields to send or creating a teacher builder with the email and password fields? I don't know if it's more efficient that way or it's the same. – Ludiras Dec 15 '19 at 20:25
  • Actually there are other differences as well. Iv'e removed @FormUrlEncoded annotation, replaced Field annotations with Body. In this case the request parameters will not be "key":"value" pairs, but will be a json object. for login, I'll suggest to change the API, to accept x-www-form-urlencoded requests, and not to change the Android code. – Aram Dec 15 '19 at 20:29
  • I will do that when I investigate how the APIs are created, I haven't touched that at the moment, although I accept recommendations of courses or places where I can learn, because I am interested. – Ludiras Dec 15 '19 at 20:32
  • 1
    Unfortunately, I'm an android developer, and cannot give more recommendations on back end :) Thanks for accepting the answer. – Aram Dec 15 '19 at 20:34