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