MrBE
MrBE

Reputation: 163

How to make post request with retrofit + moshi

I'm trying to make a post with retrofit and moshi but keep getting the error mess

com.squareup.moshi.JsonDataException: Expected BEGIN_OBJECT but was STRING at path $

I can't seem to understand why this is so. This is a sample of the json tested on postman:

{
"customerName": "Name",
"customerPhoneNo": "090000000",
"customerAddress": "Address",
"note": "Please",
"items" : [{
    "productUid": "5633e1f1-8b00-46de-b73e-43799245a4e8",
    "quantity" : "3"
},{
    "ProductUid": "fca3ffb1-0130-4e47-b499-721d046c1e32",
    "Quantity" : "5"
},
{
    "ProductUid": "6a7f3e24-03ff-408a-b67e-8530d411390c",
    "Quantity" : "2"
}]
}

My data classes are set up like so:

    @Parcelize
data class Order(
    val items: List<Item>?,
    val customerName: String,
    val customerPhoneNo: String,
    val customerAddress: String,
    val note: String
) : Parcelable

and

@Parcelize
data class Item(
    val productUid: String,
    var quantity: Int
) : Parcelable

Service utils look like:

interface ProductService {


    @Headers("Content-Type: application/json")
    @POST("/api/order/saveorder")
    suspend fun postProds(@Body order: Order
    ): Response<Order>

    @GET("/api/product/allproducts")
    suspend fun getProds(): Response<List<ProdsItem>>
}



private val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()

object Network {
    private val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(MoshiConverterFactory.create(moshi)
            .asLenient()
        )
        .build()

    object ProdsApi {
        val retrofitService: ProductService by lazy {
            retrofit.create(ProductService::class.java)
        }
    }
}

The sendOrder function is set up like so:

suspend fun sendOrder(order: Order) {
        withContext(Dispatchers.Main){
            try {
                val orderResponse = Network.ProdsApi.retrofitService.postProds(
                    order   )
              
            }
            catch (e: Exception) {
               Timber.e(e)
            }
        }
    }

The GET request works perfectly. Any help on this would be appreciated please.

Upvotes: 0

Views: 2034

Answers (2)

Yakubu
Yakubu

Reputation: 1109

Add to app/build.gradle

kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0"

Refactor your data class

check the key in your item and replace with right one

 if productUid or ProductUid
 quantity or Quantity

@JsonClass(generateAdapter = true)
data class Item(
  @Json(name = "productUid")
  val productUid: String,
  @Json(name = "quantity")
  var quantity: String
 ) 

 @JsonClass(generateAdapter = true)
 data class Order(
   @Json(name = "items")
   val items: List<Item>,
   @Json(name = "customerName")
   val customerName: String,
   @Json(name = "customerPhoneNo")
   val customerPhoneNo: String,
   @Json(name = "customerAddress")
   val customerAddress: String,
   @Json(name = "note")
   val note: String
  )

and try it again

Upvotes: 1

oyeraghib
oyeraghib

Reputation: 1073

In your Item Data Class you are using quantity as an Int but if you see the Postman JSON response it is a String.

So your class should be like:

data class Item(
 @Json(name = "productUid")
 val productUid: String?,
 @Json(name = "quantity")
 var quantity: String
)

Also as I see the key in your JSON response are written in two different ways. For example your "Product ID" is written as "productUid" in one of the object and is written as "ProductUid" in another object.

So your complete Item Data Class should more look like this :

data class Item(
    @Json(name = "productUid")
    val productUid: String?,
    @Json(name = "ProductUid")
    val productUid: String?,
    @Json(name = "quantity")
    val quantity: String?,
    @Json(name = "Quantity")
    val quantity: String?
)

Upvotes: 1

Related Questions