Search code examples
androidkotlinretrofit2

Get data from certain tag in response (Kotlin, Retrofit)


I am trying to make a simple GET API call from Android app via Retrofit and Kotlin.

What I am struggling with is getting the data from a certain tag of response.

I am using Django rest framework with pagination, therefore results are enclosed in tag results. I can't figure out how to look into this results tag i.o. the whole response from retrofit.

My response:

{
    "count": 13,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 2,
            "passport_number": 11233546,
            "first_name": "Egor",
            "last_name": "Wexler",
            "email": "string",
            "age": 0,
            "city": "city"
        },
        ...
        { <other customers> },
    ]
}

Customer.kt

import com.google.gson.annotations.SerializedName

data class Customer(
    @SerializedName("passport_number") val passportNumber: Int,
    @SerializedName("first_name") val firstName: String,
    @SerializedName("last_name") val lastName: String,
    @SerializedName("email") val email: String,
    @SerializedName("age") val age: Int,
    @SerializedName("city") val city: String
)

ApiInterface.kt

interface ApiInterface {

    @GET("customers/")
    fun getCustomers() : Call<List<Customer>>

    companion object {

        fun create() : ApiInterface {

            val retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(BASE_URL)
                .build()
            return retrofit.create(ApiInterface::class.java)
        }
    }
}

MainActivity.kt

val apiInterface = ApiInterface.create()
apiInterface.getCustomers().enqueue(
    object : Callback<List<Customer>> {
        override fun onResponse(call: Call<List<Customer>>, response: Response<List<Customer>>) {
        // logic for success
        }
        override fun onFailure(call: Call<List<Customer>>, t: Throwable) {
          t.message // java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
        }
    }
)

So the code eventually went to onFailure with the message that I put in the comment.

If I disable pagination on server - it works as expected because the response turns to what is according to app expectations (list of objects Customer).

But I want the app to look into tag results since it actually contains the response.

I feel like this should be trivial to do but can't find how.

I saw a lot of answers for the similar question marked by "Expected BEGIN_ARRAY but was BEGIN_OBJECT" but none of them solves my issue.


Solution

  • You should create a response class that follows the same structure as your response.

    In your case something like this will do:

    data class PageResult(
       val count: Int,
       val next: Int?,
       val previous: Int?,
       val results: List<Customer>
    )
    

    And in your API interface use:

    @GET("customers/")
        fun getCustomers() : Call<PageResult>