Meisam Emamjome Meisam Emamjome - 3 months ago 13
Scala Question

download a file with play web api (async)

I am trying to download a file using play api framework. Since all the data access layer has already been implemented with Futures I would like to get download to work with async action as well. However, the following piece of code does not work. And by not working I mean that the file sent to the client is not the same as the file on server.

val sourcePath = "/tmp/sample.pdf"

def downloadAsync = Action.async {
Future.successful(Ok.sendFile(new java.io.File(sourcePath)))
}


However, this piece works:

def download = Action {
Ok.sendFile(new java.io.File(sourcePath))
}


Any suggestion on how I can get the async method to work?

Answer

You actually don't need to use Action.async here, since Ok.sendFile is non-blocking already. From the docs:

Play actions are asynchronous by default. For instance, in the controller code below, the { Ok(...) } part of the code is not the method body of the controller. It is an anonymous function that is being passed to the Action object’s apply method, which creates an object of type Action. Internally, the anonymous function that you wrote will be called and its result will be enclosed in a Future.

def echo = Action { request =>
  Ok("Got request [" + request + "]")
}

Note: Both Action.apply and Action.async create Action objects that are handled internally in the same way. There is a single kind of Action, which is asynchronous, and not two kinds (a synchronous one and an asynchronous one). The .async builder is just a facility to simplify creating actions based on APIs that return a Future, which makes it easier to write non-blocking code.

In other words, at this specific case, don't worry about wrapping your Result into a Future and just return Ok.sendFile.


Finally, both versions works as expected to me (the file was properly delivered). Maybe you are having another problem not related to how you have declared your actions.

Comments