在Play 2.4项目中,我创建了一个可以做三件事的Action。
为此,我在本页中使用了Play Action组合机制解释:https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition
但更具体地说,我想要的最终结果在这里解释:
https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition#Putting-it-all-together
我成功地写了这个:
{ "errors": [
{ "code": 500, "reason": 500,
"content":
"com.orientechnologies.orient.core.exception.OSerializationException: Error on unmarshalling JSON content
'{\"transaction\":true,\"operations\":[{\"type\":\"c\",\"record\":
{\"@class': content must be between { }" } ] }
它似乎运作良好,但它并不完美,因为我强行使用package actions
import play.api.libs.concurrent.Execution.Implicits._
import play.api.libs.json._
import play.api.mvc.Results._
import play.api.mvc.{WrappedRequest, _}
import scala.concurrent.Future
object Actions {
case class WithApiKeyRequest[A](apiKey: String, request: Request[A]) extends WrappedRequest[A](request)
case class ParsedJsonRequest[A](parsed: Any, request: Request[A]) extends WrappedRequest[A](request)
def AuthenticatedAndParsed[T, A](authencation: String => Future[_])(implicit reader: Reads[T]): ActionBuilder[ParsedJsonRequest] =
WithApiKeyHeaderAction andThen AuthentificationAction(authencation) andThen JsonAction
private[this] def WithApiKeyHeaderAction = new ActionBuilder[WithApiKeyRequest] {
override def invokeBlock[A](request: Request[A], block: (WithApiKeyRequest[A]) => Future[Result]): Future[Result] =
request.headers.get("ApiKey") match {
case Some(apiKey: String) => block(WithApiKeyRequest(apiKey, request))
case _ => Future.successful { BadRequest(Json.obj("errors" -> "ApiKey header needed")) }
}
}
private[this] def AuthentificationAction(authencationFunction: String => Future[_]) = new ActionFilter[WithApiKeyRequest] {
override protected def filter[A](request: WithApiKeyRequest[A]): Future[Option[Result]] =
authencationFunction(request.apiKey)
.map { _ => None } // Do not filter the request
.recover { case _ => Some(Unauthorized) }
}
private[this] def JsonAction[T](implicit reader: Reads[T]) = new ActionBuilder[ParsedJsonRequest] {
composeParser(BodyParsers.parse.json)
override def invokeBlock[A](request: Request[A], block: (ParsedJsonRequest[A]) => Future[Result]): Future[Result] = {
request.body.asInstanceOf[JsValue].validate[T].fold(
errors => Future { BadRequest(Json.obj("errors" -> JsError.toJson(errors))) },
(parsedJson: T) => block(ParsedJsonRequest(parsedJson, request))
)
}
}
}
中的Any
类型,因为我似乎无法做到这一点:
case class ParsedJsonRequest[A](parsed: Any, request: Request[A])
有可能吗? 你认为我可以改进我的解决方案吗?怎么样?
我的问题不是关于如何做动作组合。我理解它是如何工作的,我成功地写了我的ActionBuilders和我想要的作品。 我的问题是如何改善我的作文。
感谢
朱
答案 0 :(得分:0)
我不是为JsonRequest创建新的ActionBuilder
,而是使用AuthentificationAction
ActionBuilder
并将其传递给json BodyParser
:
AuthentificationAction(parse.json) {
request => // Note that the request has type Request[JsValue]
doStuffWithJson(request.body)
}
使用此构建器的任何操作都将获得Request[JsValue]
而不是Request[AnyContent]
。