required: play.api.mvc.Request[?] => play.api.mvc.

2019-07-26 23:50发布

I am migrating to Play 2.6 and have the following API wrapper functions that used to work:

trait API {
    self: Controller =>

    def api(businessLogic: Request[AnyContent] => Any): Action[AnyContent] = apiWithBody(parse.anyContent)(businessLogic)

    def apiWithBody[A](bodyParser: BodyParser[A])(businessLogic: Request[A] => Any): Action[A] = Action(bodyParser) {
        implicit request =>
        {
            val apiResult = businessLogic(request)
            val start = new java.util.Date().getTime
            val actionDuration = (new java.util.Date().getTime - start)
            val response = resultFrom(apiResult, request, actionDuration)    // Returns a Result
            response
        }
    }
}

Called by Controller functions like:

object Accounts extends Controller with API {

    def all = superUser {
        implicit principal =>
            api {
                request =>
                    models.Account.all
            }
    }
}

Where superUser is the principal (user) type "admin".

And get the following compiler error:

[error] type mismatch;
[error]  found   : play.api.mvc.Action[play.api.mvc.AnyContent]
[error]  required: play.api.mvc.Request[?] => play.api.mvc.Result
[error]             api {
[error]                 ^

I'm building with sbt 1.1.5 and Scala 2.11.8.

I am guessing the [?] means the compiler doesn't know what type is required but I don't understand what is wrong. I have searched for this issue but not found the specific answer for this problem.

In addition I'm getting an error:

[error]  could not find implicit value for parameter parser: play.api.mvc.BodyParser[Any]
[error]     def all = superUser {
[error]                         ^

that I posted as a separate issue (see could not find implicit value for parameter parser: play.api.mvc.BodyParser[Any]) but might be relevant here?

def superUser[A](f: => Principal => Request[A] => Result)(implicit parser: BodyParser[A]): SecureAction[A] = {
    _superUser {
        user =>
            implicit val principal = data.Principal(user)
            Action(parser)(request => f(principal)(request))
    }
}

private def _superUser[A](action: String => Action[A]) = {
    play.api.mvc.Security.Authenticated(getSuperUser, onUnauthorized)(action)
}

Any help would be appreciated.

1条回答
贪生不怕死
2楼-- · 2019-07-27 00:25

Sorry I'm little bit confused here about the architecture as:

  1. Where is the API call? Is it within the model? Are you calling outside the current Play app? Why don't you use the Future API for it? Because then you can recover it. Which then help you with logging and error handling.
  2. The all method get the request, and then it does not return an HTTP response. Why don't you pass on what you need from the request (e.g., the Cookie).
  3. I think the answer to your question is to use your action composition with action. Something like:

    def myMethod(queryParam: String) = myDefinedAction compose Action { ??? } 
    
    //In case you want to use the Future API, then you need to be async
    def myMethod(queryParam: String) = (myDefinedAction compose Action).async {
      implicit request => 
         apiCall.map{
           case _ => Ok("good request") 
         }.recover{case _ => BadRequest} 
    
    } 
    
查看更多
登录 后发表回答