I'm going to assume here that you mean for the strings to be concatenated. First some comments on the code:
There's no need to wrap the whole block in an Async, just the final future that you're returning.
The value types can all be inferred, you don't need to state them explicitly
mapping a
List
returns aList
. CallingtoList
on the result is redundant.List#sum
only works on numbers, usefoldLeft
instead for strings.A
Future[String]
can not be cast directly to aString
viaasInstanceOf
. You'll be returning it as aFuture
anyway.map
andFuture.sequence
can be combined into a singleFuture.traverse
operation.
And changing the code to apply these points:
def futuresTest(strList: List[String]) = Action {
val ftrList = Future.traverse(strList) {
s => Future( longRunningCall(s) )
}
// this will be a Future[String]
val jsonResponse = ftrList map { _.foldLeft("")(_ + _) }
Async { jsonResponse map (OK(_)) }
}
The last two lines could also be combined:
Async {
ftrList map { xs => OK(xs.foldLeft("")(_ + _)) }
}
UPDATE
Here's the same thing using Future.fold, as suggested by Viktor
def futuresTest(strList: List[String]) = Action {
val ftrList = strList map { longRunningCall(_) } // List[Future]
val jsonResponse = Future.fold(ftrList)("")(_ + _) // Future[String]
Async { jsonResponse map (OK(_)) }
}
For handling failure, you want to recover the future and have it return a different response:
Async { jsonResponse map (OK(_)) recover (InternalServerError(_.toString)) }
If you want to handle individual errors from each element, then you should look at the technique used in this answer.