Reputation: 3400
I would like to catch exception and redirect to a custom page in the following code. However, exceptions are not caught/seen.
def addItemWithParts(item: Item, parts: Seq[String]): Future[Int] = {
... // May throw exceptions
}
def handleAddItem = auth.SecuredAction.async { implicit request =>
itemForm.bindFromRequest.fold(
formWithErrors => {
Future.successful(
Redirect(controllers.www.routes.ItemController.startAddItem()).flashing(
"error" -> "Bad item add input"
)
)
},
item => {
for {
ue <- usersService.findUserEntryByEmail(request.identity.email)
} yield ue match {
case Some(ue) =>
val itemObj = Item(item.name, item.description, ue.companyId)
val xx = itemsService.addItemWithParts(itemObj, Seq(item.parts)) <-- want to catch exception thrown by this function
/*
* COMMENTED CODE PRINTS EXCEPTION ON CONSOLE, BUT DONT KNOW HOW TO REDIRECT/OK...
xx onComplete {
case Success(x) => {
println("Added ITEM: " + x)
Redirect(controllers.www.routes.Dashboard.dashboard)
}
case Failure(exp) => {
println("Exception while adding ITEM: " + exp)
Ok("Got exception: " + exp)
}
}
*/
Redirect(controllers.www.routes.Dashboard.dashboard) // +++
case None =>
Ok("Bad")
}
}
)
}
I thought I can do Redirect() from onComplete success instead of at line marked "+++" but I get this compilation error:
type mismatch;
[error] found : Unit
[error] required: play.api.mvc.Result
[error] case Some(ue) =>
[error] ^
[error] one error found
I checked play documentation, it talks about adding onServerError to ErrorHandler (centralized) but I want to know what I am missing in doing it this way.
I am still learning Scala, any help is deeply appreciated.
Upvotes: 0
Views: 418
Reputation: 14825
onComplete
returns Unit
. You can do only side effecting operations using onComplete
.
Use map
, flatMap
for composing and building new computations. Use recover
and recoverWith
to handle exceptions and return something on exceptions.
here is how you can do this
val result =
for {
ueOpt <- usersService.findUserEntryByEmail(request.identity.email)
result <- ueOpt match {
case Some(ue) =>
val itemObj = Item(item.name, item.description, ue.companyId)
val foo = itemsService.addItemWithParts(itemObj, Seq(item.parts))
foo.map { value =>
Redirect(controllers.www.routes.Dashboard.dashboard)
}.recover { case th =>
InternalServerError("bad things happen in life.")
}
case None => Future.successful(BadRequest("no item found"))
}
} yield result
Future
provides methods like map
, flatMap
to build new computations with result of the current future. Also future provides recover
and recoverWith
to build computations when current future throws exceptions.
def bar: Future[Int] = ???
bar.map { intValue =>
//doSomething
}.recover {
case ex: SQLException => //return some value
case _ => //ignore other exceptions and return default value
}
Upvotes: 1