Reputation: 1887
I have a method that produces an Action validating if a user token exist in the request:
def HasToken[A](p: BodyParser[A] = parse.anyContent)(
f: String => Long => Request[A] => Result): Action[A] =
Action(p) { implicit request =>
request.cookies.get("XSRF-TOKEN").fold {
invalidXSRF
} { xsrfTokenCookie =>
val maybeToken = request.headers.get(AuthTokenHeader).orElse(request.getQueryString(AuthTokenUrlKey))
maybeToken flatMap { token =>
cache.get[Long](token) map { userId =>
if (xsrfTokenCookie.value == token) {
f(token)(userId)(request)
} else {
invalidToken
}
}
} getOrElse noCookie
}
}
Then I can use this action in my controller like this:
def method = HasToken(parse.empty) {
token => userId => implicit request => Ok("")
}
But I started using reactive-mongo in the project and all the queries to the database return a Future. What I think is really good. In order to validate the user while using this reactive-api I had to write a new Action validation method like this:
def AsyncHasToken[A](p: BodyParser[A] = parse.anyContent)(
f: String => Long => Request[A] => Future[Result])(implicit ec: ExecutionContext): Action[A] =
Action.async(p) { implicit request =>
request.cookies.get("XSRF-TOKEN").fold {
Future(invalidXSRF)
} { xsrfTokenCookie =>
val maybeToken = request.headers.get(AuthTokenHeader).orElse(request.getQueryString(AuthTokenUrlKey))
maybeToken flatMap { token =>
cache.get[Long](token) map { userId =>
if (xsrfTokenCookie.value == token) {
f(token)(userId)(request)
} else {
Future(invalidToken)
}
}
} getOrElse Future(noCookie)
}
}
So, when I need to return a Future in my controller methods I use it like this:
def method() = AsyncHasToken(parse.empty) {
token => userId => implicit request => Future(Ok(""))
}
After many hours trying to refactor HasToken and AsyncHasToken I havent been able to produce satisfactory results. Is there a way to write this code more elegantly?
I think the question is more related to refactoring scala functions than Playframework, but I feel that I will be facing this pattern a lot when writing generic Actions and Async Actions thru my project.
Thanks in advance.
Upvotes: 0
Views: 87
Reputation: 2404
For this I would use the Play ActionBuilder
, it will allow you to keep the logic in one place and use your action with both Result
and Future[Result]
.
cf: https://playframework.com/documentation/2.4.x/ScalaActionsComposition
Upvotes: 1