Question

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")
            }
        }
      }
    }
 }
Was it helpful?

Solution

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("") } }

OTHER TIPS

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")
        }
      }
    }
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top