scala - una - la variable aleatoria binomial mide:
Jugar: Cómo implementar la composición de acción (3)
La función async
espera un Future[SimpleResult]
, pero la SecuredAction.async
anidada está devolviendo una Action
a la parte superior SignedAction.async
(observa que en su código de muestra omite declarar las solicitudes como class
y SignedAction
se declara dos veces).
Puede componer el resultado de SecuredAction
anidado dentro de SignedAction
al aplicarlo a la solicitud firmada.
package controllers
import scala.concurrent.Future
import play.api._
import play.api.mvc._
case class SignedRequest[A](request: Request[A])
extends WrappedRequest[A](request) {}
object SignedAction extends ActionBuilder[SignedRequest] {
def invokeBlock[A](request: Request[A],
block: SignedRequest[A] => Future[Result]) =
block(new SignedRequest(request))
}
case class SecuredRequest[A](request: Request[A])
extends WrappedRequest[A](request) {}
object SecuredAction extends ActionBuilder[SecuredRequest] {
def invokeBlock[A](request: Request[A],
block: SecuredRequest[A] => Future[Result]) =
block(new SecuredRequest(request))
}
object MyController extends Controller {
def doSomething = SignedAction.async(parse.json) { signedReq =>
SecuredAction.async(parse.json) { implicit securedReq =>
Future.successful(Ok)
} apply signedReq
}
}
Tal composición de acción también se puede hacer sin ActionBuilder
(lo que puede llevar a una complejidad adicional).
package controllers
import scala.concurrent.Future
import play.api._
import play.api.mvc._
case class SignedRequest[A](request: Request[A])
case class SecuredRequest[A](request: Request[A])
object MyController extends Controller {
def Signed[A](bodyParser: BodyParser[A])(signedBlock: SignedRequest[A] => Future[Result]): Action[A] = Action.async(bodyParser) { req =>
signedBlock(SignedRequest(req))
}
def Secured[A](bodyParser: BodyParser[A])(securedBlock: SecuredRequest[A] => Future[Result]): Action[A] = Action.async(bodyParser) { req =>
securedBlock(SecuredRequest(req))
}
def doSomething = Signed(parse.json) { signedReq =>
Secured(parse.json) { implicit securedReq =>
Future.successful(Ok)
} apply signedReq.request
}
}
La composición también se puede hacer en Future[Result]
:
package controllers
import scala.concurrent.Future
import play.api._
import play.api.mvc._
import play.api.libs.json.JsValue
case class SignedRequest[A](request: Request[A])
case class SecuredRequest[A](request: Request[A])
object MyController extends Controller {
def Signed[A](signedBlock: SignedRequest[A] => Future[Result])(implicit req: Request[A]): Future[Result] = signedBlock(SignedRequest(req))
def Secured[A](signedBlock: SecuredRequest[A] => Future[Result])(implicit req: Request[A]): Future[Result] = signedBlock(SecuredRequest(req))
def doSomething = Action.async(parse.json) { implicit req =>
Signed[JsValue] { signedReq =>
Secured[JsValue] { securedReq => Future.successful(Ok) }
}
}
}
Dadas las ActionBuilder
implementaciones de ActionBuilder
:
class SignedRequest[A](request: Request[A]) extends WrappedRequest[A](request) {}
object SignedAction extends ActionBuilder[SignedRequest] {
def invokeBlock[A](request: Request[A], block: SignedRequest[A] => Future[SimpleResult]) = {
block(new SignedRequest(request))
}
}
class SecuredRequest[A](request: Request[A]) extends WrappedRequest[A](request) {}
object SecuredRequest extends ActionBuilder[SecuredRequest] {
def invokeBlock[A](request: Request[A], block: SecuredRequest[A] => Future[SimpleResult]) = {
block(new SecuredRequest(request))
}
}
¿Cómo los combino? He intentado lo siguiente ...
object MyController extends Controller {
def doSomething = SignedAction.async(parse.json) {
SecuredAction.async(parse.json) { implicit request =>
Future.successful(Ok)
}}
}
... pero siempre aparece el siguiente mensaje de error:
/home/j3d/test/controllers/MyController.scala:37: type mismatch;
[error] found : play.api.mvc.Action[play.api.libs.json.JsValue]
[error] required: scala.concurrent.Future[play.api.mvc.SimpleResult]
[error] SecuredAction.async(parse.json) {
^
¿Me estoy perdiendo de algo? Tx.
Usando action-zipper puedes componer ActionBuilders
import jp.t2v.lab.play2.actzip._
object MyController extends Controller {
val MyAction = SignedAction zip SecuredAction
def doSomething = MyAction.async(parse.json) { case (signedReq, secureReqeq) =>
Future.successful(Ok)
}
}
El análisis Json es solo una vez :)
para simplificar la respuesta de @applicius, creo que se puede hacer sin el futuro, creo que asincrónico / futuro es una preocupación aparte.
Simplemente eliminando Futures y async, obtenemos esto:
def signed[A](signedBlock: SignedRequest[A] => Result)(implicit req: Request[A]) = signedBlock(SignedRequest(req))
def secured[A](securedBlock: SecuredRequest[A] => Result)(implicit req: Request[A]) = securedBlock(SecuredRequest(req))
//the use is the same as with Futures except for no async
def doSomething = Action(parse.json) { implicit req =>
signed[JsValue] { signedReq => secured[JsValue] { securedReq =>
Ok
} } }