Hi guys. This is my first time playing with corout...
# codereview
m
Hi guys. This is my first time playing with coroutines and my use case is the following: I want to have an endpoint that returns a users documents as a zip of PDFs. So first I fetch all document IDs, then I want to run a coroutine to fetch each document by ID. I have a working implementation (snippet below), but I feel that there should be a more idiomatic way of doing this. Does anyone have any thoughts? Not sure if this post is best suited here or in the #coroutines channel, but I'll give it a go here! Any input is much appreciated.
Copy code
@GetMapping(value = ["download-all"], produces = ["application/zip"])
    fun downloadAll(): ByteArray {
        val outputStream = ByteArrayOutputStream(1024)
        val bufferedOutputStream = BufferedOutputStream(outputStream)
        val zipOutputStream = ZipOutputStream(bufferedOutputStream)

        val docIds = docService.getDocIds()

        runBlocking {
            val docStream = docIds
                .map { GlobalScope.async { docService.getDoc(it) } }
                .map { ByteArrayInputStream(it.await()) }
                .map { BufferedInputStream(it) }

            docStream.forEachIndexed { index, bufferedInputStream ->
                val zipEntry = ZipEntry("test${index}.pdf")
                zipOutputStream.putNextEntry(zipEntry)
                bufferedInputStream.copyTo(zipOutputStream, 1024)
                bufferedInputStream.close()
                zipOutputStream.closeEntry()
            }
            zipOutputStream.close()
        }

        return outputStream.toByteArray()
    }
d
I got a bit carried away but this is how i'd rewrite it.
Copy code
@GetMapping(value = ["download-all"], produces = ["application/zip"])
fun downloadAll(): ByteArray {
    val outputStream = ByteArrayOutputStream(1024)
    runBlocking {
        val docBytes = docService.getDocIds()
            .map { async { docService.getDoc(it) } }
            .awaitAll()

    	ZipOutputStream(outputStream).use { output ->
            docBytes.forEachIndexed { index, bytes ->
                val zipEntry = ZipEntry("test${index}.pdf")
                output.putNextEntry(zipEntry)
                output.write(bytes)
                output.closeEntry()
            }
        }
    }
    return outputStream.toByteArray()
}
m
Wow, thanks a lot! This definitely look much cleaner! 🙂