Home > database >  What is the right way to post with retrofit 2 and moshi
What is the right way to post with retrofit 2 and moshi

Time:04-05

I've been trying to make a POST with Retrofit 2 and Moshi but I've been unable to get it to work. My data classes look like this:

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

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

The interface looks like this

interface ProductService {

    @POST("/api/order/saveorder")
    suspend fun postProds(
       @Field("customerName") customerName: String,
        @Field("customerPhoneNo") customerPhone: String,
        @Field("customerAddress") address: String,
        @Field("note") customerNote:String,
        @Field("items") orderItems: List<Item>

    ): 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 postProds fun is called like this:

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

Trying to POST this way keeps yielding this response:

Response{protocol=h2, code=400, message=, url=

However, I tried converting the Order object to json directly in my viewModel as follows:

val moshi: Moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
        val jsonAdapter: JsonAdapter<Order> = moshi.adapter(Order::class.java)

        val jsonString = jsonAdapter.toJson(customerOrder)
        Timber.d(jsonString)

I then tested the generated jsonString on Postman and got a 200 response.

I need some help figuring out what I'm doing wrong in my code, please.

CodePudding user response:

In postman, you are sending data in the body of the request. But in your code, it is going as key-value params. Try to send it in the body from your code. Try below snippet.

Update your Order Data class:

@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
)

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

    @Json(name = "quantity")
    var quantity: Int
)

Now the ProductService Interface:

interface ProductService {

    @POST("/api/order/saveorder")
    suspend fun postProds(
      @Body request: Order
    ): Response<Order>

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

Now Pass the request object in your function call:

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