1

I am trying to implement user register on my app using Retrofit, i however keep getting this error not sure whats wrong, java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY

This is the response from postman

{
"isSuccessful": true,
"message": "successful",
"user": {
    "name": "Jackline Jazz",
    "email": "[email protected]",
    "phone": "000000"
}

}

I have two model classes the User model class

data class User(
val name: String,
val email:String,
val phone:String

)

And the login response class

data class LoginResponse(
val isSuccessful:Boolean,
val message: String,
val user: List<User>

)

my Retrofit object

object RetrofitClient {

private const val BASE_URL = "http://10.0.2.2:7000/"

val instance: RetrofitApi by lazy {
    val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

retrofit.create(RetrofitApi::class.java)
}

}

Retrofit api

@FormUrlEncoded
@POST("users/register")
fun userRegister(
    @Field("name") name: String,
    @Field("email") email: String,
    @Field("password") password: String,
    @Field("confirmPassword") confirmPassword: String
): Call<LoginResponse>

and my register class

RetrofitClient.instance.userRegister(name, email, password, confirmPassword)
            .enqueue(object : Callback<LoginResponse> {
                override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
                    Toast.makeText(applicationContext, t.message, Toast.LENGTH_LONG).show()`
                }

                override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
                    if (response.body()?.isSuccessful!!){

                        val intent = Intent(applicationContext, MainActivity::class.java)

                        startActivity(intent)

                    }else{
                        Toast.makeText(applicationContext, response.body()?.message, Toast.LENGTH_LONG).show()
                    }
                }

            })
    }
}

And if possible someone help me implement Kotlin coroutines

2 Answers 2

3

In your previous question, you were hitting a users/login endpoint. You created a LoginResponse that modeled the response from the server. There, users/login returns a List<User>, so LoginResponse had to be set up that way.

Now, you are hitting a users/register endpoint... but you are still trying to use LoginResponse. As you can see from your JSON, you are getting different JSON from the server, where there is only one user. As a result, you need a different response class (e.g., RegisterResponse) that models this new response:

data class RegisterResponse(
  val isSuccessful:Boolean,
  val message: String,
  val user: User
)

@FormUrlEncoded
@POST("users/register")
fun userRegister(
    @Field("name") name: String,
    @Field("email") email: String,
    @Field("password") password: String,
    @Field("confirmPassword") confirmPassword: String
): Call<RegisterResponse>
Sign up to request clarification or add additional context in comments.

2 Comments

CommonsWare, providing ongoing debugging help for new users since 2009 :D
@ToshGitonga: Then your RegisterResponse does not match the JSON. Note that your error message also does not match the JSON -- the error says it encountered an array, but the JSON shown in your question does not contain an array. Therefore, the error is referring to some different JSON than what you have in your question.
0

BEGIN_ARRAY means there is some JSON returned that contains a JSON Array ([]) where your object schema expects a JSON object ({}). Sometimes APIs return different responses based on the client they're dealing with, so it's better to debug the issue at hand in your code. One way of doing this would be to temporarily use Retrofit's scalar converter factory.

Add this dependency:

dependencies {
    implementation 'com.squareup.retrofit2:converter-scalars:<your-retrofit-version>'
}

and this code

val retrofit = new Retrofit.Builder()  
        .addConverterFactory(ScalarsConverterFactory.create())
        ...

and return a Callable<String> instead of your custom type and log what is actually returned from your server. Then you can act upon accordingly.

2 Comments

I used a httpinterceptor and what is being returned from the server is exactly same as the postman response
Ah, my bad, I saw it too late: You have val user: List<User> in your model, but you want val user: User instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.