Reputation: 453
I am in the process of trying to upgrade Play Framework from 2.1 to 2.2 and are running into difficulties with the new Action.asyc syntax. An example problem
I get:
->Action.async {
type mismatch; found : play.api.mvc.Action[play.api.mvc.AnyContent]
required: scala.concurrent.Future[play.api.mvc.SimpleResult]
After lots of Google, am switching to the SO community. Example code passage (lots of irrelevant detail stripped out) here:
Play 2.1
def homeContent(origin: String, segment: String) = Secured {
Action {
implicit request =>
val maybeOrigin = Origin.allOrigins.find(p => p.slug == origin)
maybeOrigin match {
case None => NotFound
case Some(originPlace) => {
val futureResult = scala.concurrent.Future {
DealCard.getTopDealCardsFor(origin, segment)
}
Async {
futureResult.map {
case (topDeals) =>
Ok(“”).as("application/json")
}
}
}
}
}
}
Play 2.2.2
def homeContent(origin: String, segment: String) = Secured {
Action.async {
implicit request =>
val maybeOrigin = Origin.allOrigins.find(p => p.slug == origin)
maybeOrigin match {
case None => Future.successful(NotFound)
case Some(originPlace) => {
Action.async {
val futureResult = scala.concurrent.Future {
DealCard.getTopDealCardsFor(origin, segment)
}
futureResult.map {
case (topDeals) =>
Ok("").as("application/json")
}
}
}
}
}
Upvotes: 1
Views: 701
Reputation: 619
I just wrote an example app that might be helpful on my Github. The main idea is laid out below:
Normal actions in Play either expect an Action or a SimpleResult
def normal = Action { Ok("") }
Secured, the way you have it implemented, is expecting an Action
def secured = Secured { Action { Ok("") } }
And Action.async expects a Future of a SimpleResult, but still returns an Action
def async = Action.async { Future { Ok("") } }
What you seem to be looking for is a Secured that takes a Future[SimpleResult]. To do that you should try to follow the example laid out in the Play documentation for Action Composition for
trait Security {
class AuthenticatedRequest[A](val username: String, request: Request[A]) extends WrappedRequest[A](request)
object Secured extends ActionBuilder[AuthenticatedRequest] {
def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) => Future[SimpleResult]) = {
request.session.get("username").map { username =>
block(new AuthenticatedRequest(username, request))
} getOrElse {
Future.successful(Results.Forbidden)
}
}
}
}
Then you should be able to compose something like this:
def securedAsync = Secured.async { Future { Ok("") } }
Upvotes: 2
Reputation: 7247
The problem is that your Action.async
is within another Action
block. Your overall block needs to be Action.async
within which you'll return a Future
of a Result
, e.g., Ok
, NotFound
, etc.
edit: This is what you're supposed to do:
def homeContent(origin: String, segment: String) = Secured {
Action.async { implicit request =>
val maybeOrigin = Origin.allOrigins.find(p => p.slug == origin)
maybeOrigin match {
case None => Future.successful(NotFound)
case Some(originPlace) => {
DealCard.getTopDealCardsFor(origin, segment) map { topDeals =>
Ok("").as("application/json")
}
}
}
}
}
Upvotes: 1