Play Framework 2.4 Scala missing parameter type for implicit request in Action after ActionRefiner

Viewed 1014

I've made ActionRefiner to read language of current request from parameter in url:

class LangRequest[A](val lang: Lang, request: Request[A]) extends WrappedRequest[A](request)

  def LangAction(lang: String) = new ActionRefiner[Request, LangRequest] {
    def refine[A](input: Request[A]) = Future.successful {
      val availLangs: List[String] = Play.current.configuration.getStringList("play.i18n.langs").get.toList
      if (!availLangs.contains(lang))
        Left {
          input.acceptLanguages.head match {
            case Lang(value, _) if availLangs.contains(value) => Redirect(controllers.routes.Application.index(value))
            case _ => Redirect(controllers.routes.Application.index(availLangs.head))
          }
        }
      else Right {
        new LangRequest(Lang(lang), input)
      }
    }
  }

and try to use it in action like this:

  def login(lng: String) =
      LangAction(lng) {
        implicit request =>
        Ok("Ok")
      }

And here I get this "missing parameter type" error for implicit request What I'm doing wrong? Thanks in advance

1 Answers

Note: I am new to Play/Scala. There may be a simpler solution.

Likely you had same scenario as me. Initially tried to implement code similar to examples in https://www.playframework.com/documentation/2.6.x/ScalaActionsComposition#Putting-it-all-together

The difficulty is in implementing shorter action chains than their 'putting it all together'. For example I just needed to refine action based on an ID, but I didn't need any auth.

So rather than having userAction andThen ItemAction(itemId) andThen PermissionCheckAction, I just needed ItemAction(itemId)

I ran into same error as you trying to naively remove the other 2 action funcs. I believe the issue is that userAction in guide specifies/define what body-parser the request will use.

By removing this part, your request doesn't know what type of body-parser, so it doesn't know the [A] of request[A], hence complaining about type

My Fix: Use an action class (rather than just function), that can have a body-parser passed into constructor

class LeagueRequest[A](val league: League, request: Request[A]) extends WrappedRequest[A](request)

class LeagueAction(val parser: BodyParser[AnyContent], leagueId: String)(implicit val ec: ExecutionContext) extends ActionBuilder[LeagueRequest, AnyContent] with ActionRefiner[Request, LeagueRequest]{
  def executionContext = ec
  override def refine[A](input: Request[A]) = Future.successful {
    inTransaction(
      (for {
        leagueIdLong <- IdParser.parseLongId(leagueId, "league")
        league <- AppDB.leagueTable.lookup(leagueIdLong).toRight(NotFound(f"League id $leagueId does not exist"))
        out <- Right(new LeagueRequest(league, input))
      } yield out)
    )
  }
}

with my controller having

def get(leagueId: String) = (new LeagueAction(parse.default, leagueId)).async { implicit request => 
     Future(Ok(Json.toJson(request.league)))
}

I could not manage to avoid OP's error using action composition functions, rather than class that extended ActionBuilder.

Related