J.Doe
J.Doe

Reputation: 299

How to set body of HttpServletResponse using ktor client

I have spring boot controller

@PostMapping(path = ["/download"])
fun getFile(@RequestBody myObjectRq: myObjectRq, httpServletResponse: HttpServletResponse): CompletableFuture<HttpServletResponse> {
    return GlobalScope.async {
       val response = webService.getFile(myObjectRq)
       response?.let {
           httpServletResponse.setHeader("Content-Type", response.headers.get("Content-Type"))
           httpServletResponse.setHeader("Content-Disposition", response.headers.get("Content-Disposition"))
           httpServletResponse.writer.write(String(response.content.toByteArray()))
           httpServletResponse.writer.flush()
           httpServletResponse.status = response.status.value
       }
       httpServletResponse
   }.asCompletableFuture()
}

in which I use service which in turn uses ktor client to send post request to external server which should respond sending csv file. csv file content depends on values I send in myObjectRq.

Service:

suspend fun getFile(myObjectRq: myObjectRq): HttpResponse {
    val response = ktorClient.post<HttpResponse> {
        accept(ContentType.Application.OctetStream)
        url(externalWebServerUrl)
        body = myObjectRq
        contentType(ContentType.Application.Json)
    }
    log.info(String(response.content.toByteArray()))
    response
}

Headers in response are properly set, also log.info(String(response.content.toByteArray())) in the method prints out the content of received file, but I can't set it as a body of HttpServletResponse. I keep getting org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation.

Also I get Inappropriate blocking method call for httpServletResponse.writer which kind of breaks async qualities of ktor client. What do I do wrong? How should I solve it?

Upvotes: 0

Views: 2235

Answers (2)

J.Doe
J.Doe

Reputation: 299

I actually managed to solve this using CompletableFuture<ResponseEntity<ByteArray>> as return type and setting body of the response this way: ResponseEntity.ok().body(response.content.toByteArray()) This also removed Inappropriate blocking method call warnings.

Upvotes: 0

Trein
Trein

Reputation: 3688

So, I think SpringBoot is confused with your return type. It is trying to find a way to serialize your return CompletableFuture<HttpServletResponse> into the body of the HTTP response but failing. I believe you can achieve the same result by changing your implementation as follows:

@PostMapping(path = ["/download"])
fun getFile(@RequestBody myObjectRq: myObjectRq, httpServletResponse: HttpServletResponse): CompletableFuture<Void> {
    return GlobalScope.async {
       val response = webService.getFile(myObjectRq)
       response?.let {
           httpServletResponse.setHeader("Content-Type", response.headers.get("Content-Type"))
           httpServletResponse.setHeader("Content-Disposition", response.headers.get("Content-Disposition"))
           httpServletResponse.writer.write(String(response.content.toByteArray()))
           httpServletResponse.writer.flush()
           httpServletResponse.status = response.status.value
       }
       null
   }.asCompletableFuture()
}

Upvotes: 1

Related Questions