Why it fails actually matters 100%. If we spread the code over a number of lines of code, you'll understand why:
def getStuff(userId: String) = Action(implicit request => {
Async {
val future = UserDao().getStuffOf(userId = userId).toList()
val mappedFuture = future.map {
stuffLst => Ok(stuffLst)
}
mappedFuture.recover { case _ => BadRequest("")}
}
})
So, UserDao().getStuffOf(userId = userId).toList()
returns you a future. A future represents something that may not have happened yet. If that thing throws an exception, you can handle that exception in recover. However, in your case, the error is happening before the future is even being created, the UserDao().getStuffOf(userId = userId).toList()
call is throwing an exception, not returning a future. So the call to recover the future will never be executed. It's equivalent to doing this in the Scala repl:
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
var f = { throw new Exception(""); future { "foo" } map {_ => 2} recover { case _ => 1} }
Await.result(f, 1 nanos) }
Obviously that doesn't work, since you never created the future in the first place beacuse the exception was thrown before the code to create the future happened.
So the solution is to either wrap your call to UserDao().getStuffOf(userId = userId).toList()
in a try catch block, or find out why it's failing in whatever method you're calling, and catch the exception there, and return a failed future.