There's a bunch of ways to solve this problem. I'll give you one possibility. Consider this cleaned up version of your code:
trait Result
case class BadRequest(message:String) extends Result
case class InternalServerError(message:String) extends Result
case class Created(message:String) extends Result
def processRequest(json:String):Result = {
val result =
for{
user <- Try(parseJson(json))
savedUser <- Try(saveToDb(user))
} yield Created("saved")
result.recover{
case jp:JsonParsingException => BadRequest(jp.getMessage)
case other => InternalServerError(other.getMessage)
}.get
}
def parseJson(json:String):User = ...
def saveToDb(user:User):User = ...
The caveat to this code is that it assumes that you can differentiate the json parsing failure from the db failure by the exception each might yield. Not a bad assumption to make though. This code is very similar to a java try/catch block that catches different exception types and returns different results based on catching those different types.
One other nice thing about this approach is that you could just define a standard recovery Partial Function for all kinds of possible exceptions and use it throughout your controllers (which I'm assuming this code is) to eliminate duplicate code. Something like this:
object ExceptionHandling{
val StandardRecovery:PartialFunction[Throwable,Result] = {
case jp:JsonParsingException => BadRequest(jp.getMessage)
case sql:SQLException => InternalServerError(sql.getMessage)
case other => InternalServerError(other.getMessage)
}
}
And then in your controller:
import ExceptionHandling._
result.recover(StandardRecovery).get