I have a requirement to get the data from database and create CSV file of data and return it and the file should be downloaded. and get deleted from server after response has been sent. I used this Simple CSV streaming example
Code snippet:
def getAllRetailersCsvData: Route =
post {
entity(As[String]) { body =>
//removed database calls and added data from db
val retailersInformation = RetailersInformation(
List(
RetailerInformation(Target,277,8360.56,267.12),
RetailerInformation(Amazon,85,1370.0,540.11),
RetailerInformation(Walmart,77,1431.32,344.38),
RetailerInformation(Best buy,63,1213.22,160.84),
RetailerInformation(Others,22,391.77,108.1),
RetailerInformation(Others,17,317.86,157.93),
RetailerInformation(Ebay,4,46.97,14.55),
RetailerInformation(Big lots,3,24.0,12.33),
RetailerInformation(Smith's,2,44.98,218.43),
RetailerInformation(Kroger,2,39.98,29.09)),23)
implicit val retailerAsCsv = Marshaller.strict[RetailersInformation, ByteString] { t =>
Marshalling.WithFixedContentType(ContentTypes.`text/csv(UTF-8)`, () => {
ByteString(t.retailersInformation.map(r => csvData(r)).mkString("\n"))
})
}
implicit val csvStreaming: CsvEntityStreamingSupport = EntityStreamingSupport.csv()
val eventualRetailersInfo = Future(retailersInformation)
onComplete(eventualRetailersInfo) {
case Success(info: RetailersInformation) =>
complete(Source.single(info))
case Failure(exception) =>
logger.error(s"Got an exception when getting all retailers info by $campaignId , exception $exception")
complete(HttpResponse(InternalServerError, entity = generate(ErrorResponse(ErrorMessage))))
}
}
}
The issue is when I hit the route from the postman, I get the correct content but not csv file.
Output:
Retailer Name,Receipts Submitted,Brand Total,Basket Size
"Target","277","267.12","8360.56"
"Amazon","85","540.11","1370.0"
"Walmart","77","344.38","1431.32"
"Best buy","63","160.84","1213.22"
"Others","22","108.1","391.77"
"Others","17","157.93","317.86"
"Ebay","4","14.55","46.97"
"Big lots","3","12.33","24.0"
"Smith's","2","218.43","44.98"
"Kroger","2","29.09","39.98"
I have a few different things from streaming csv example. I have a post request. Not sure where to set the header that accepts only csv text. If I am making accept please guide me as I am a beginner to Akka stream concepts. Any help will be appreciated.
Thanks
To resolve this issue, first I create a file to pass as an HTTP response.
def writeToFile(content: String, campaignId: String): File = {
val tempFolder = System.getProperty(TempDir)
val file = new File(s"$tempFolder/retailers_$campaignId.csv")
val bw = new BufferedWriter(new FileWriter(file))
bw.write(content)
bw.close()
file
}
def retailersInfoForCsvResponseHandler(response: Either[Throwable, Option[String]], campaignId: String): HttpResponse =
response.fold({ err =>
logger.error(s"An exception has occurred while getting retailersInfo for csv from snap3 service ${err.getMessage}")
HttpResponse(StatusCodes.InternalServerError, entity = err.getMessage)
}, response => {
val file = writeToFile(response.fold("")(identity), campaignId)
val source = FileIO.fromPath(file.toPath)
.watchTermination() { case (_, result) =>
result.onComplete(_ => file.delete())
}
HttpResponse(status = StatusCodes.OK, entity = HttpEntity(ContentTypes.`text/csv(UTF-8)`, source))
})
It worked for me. And file sent as response and file get deleted after a response has been sent.