I'm attempting to deserialize a JSON list of strings into the body of a ktor POST request for testing. However I get the following error:
java.lang.IllegalStateException: Fail to serialize body. Content has type: class java.util.Collections$SingletonList, but OutgoingContent expected.
If you expect serialized body, please check that you have installed the corresponding feature(like `Json`) and set `Content-Type` header.)
Any suggestions?
Here is my test setup:
import io.ktor.client.HttpClient
import io.ktor.client.engine.mock.MockEngine
import javax.inject.Singleton
@Provides
@Singleton
fun provideKtorHttpClient(
mockEngine: MockEngine
): HttpClient {
return HttpClient(mockEngine) {
install(JsonFeature) {
serializer = KotlinxSerializer()
acceptContentTypes = listOf(
ContentType.parse("application/vnd.any.response json"),
ContentType.parse("application/json")
)
}
}
}
@Provides
@Singleton
fun mockEngine(): MockEngine {
val mockEngine = MockEngine { request ->
when {
request.url.fullPath.endsWith("lorem") -> {
val body = request.body as TextContent
val words: List<String> = Json.decodeFromString(body.text)
when (words[0]) {
"Foo" -> respond(
content = ByteReadChannel("Ok"),
status = HttpStatusCode.OK,
headers = headersOf(HttpHeaders.ContentType, "application/json")
)
else ->
respond(
content = ByteReadChannel("Not found"),
status = HttpStatusCode.NotFound,
headers = headersOf(HttpHeaders.ContentType, "application/json")
)
}
}
}
}
}
class MyApi @Inject constructor(
private val httpClient: HttpClient
) {
suspend fun postData(words: List<String>): Either<Exception, String> = Either.catch {
httpClient.post<String>("https://foo.bar/api/lorem") {
body = words
}
}
}
@Test
fun testApiOk() = runBlocking {
val myApi = MyApi(httpClient, networkingConstants)
runBlocking {
val result = myApi.postData(listOf("Foo"))
assertTrue(result.isRight())
}
}
CodePudding user response:
Just add the Content-Type
header to the request builder so the JsonFeature
will serialize the body.
suspend fun postData(words: List<String>): Either<Exception, String> = Either.catch {
httpClient.post<String>("https://foo.bar/api/lorem") {
body = words
contentType(ContentType.Application.Json)
}
}