【发布时间】:2016-04-14 08:44:44
【问题描述】:
在一个 Play 2.4 项目中,我创建了一个执行三件事的动作。
- 检查是否存在特定的标头。如果不是,则返回 HTTP 错误。
- 使用标头值对用户进行身份验证(身份验证函数将传递给该操作)。如果身份验证失败,则返回 HTTP 错误
- 将 JSON 主体解析为案例类,并将其提供给 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
我写成功了:
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))
)
}
}
}
它似乎运行良好,但并不完美,因为我不得不在 case class ParsedJsonRequest[A](parsed: Any, request: Request[A]) 中使用 Any 类型,因为我似乎不能这样做:
case class ParsedJsonRequest[T, A](parsed: T, request: Request[A])
有可能这样做吗? 你认为我可以改进我的解决方案吗?怎么样?
我的问题不是关于如何进行动作组合。我了解它是如何工作的,并且我成功地编写了我的 ActionBuilders 和我想要的组合。 我的问题是关于如何改进我的作文。
谢谢
朱尔斯
【问题讨论】:
-
不,因为这篇文章只解释了一个简单的动作组合案例,不回答我的问题。
-
它是组合动作,使用
BodyParser,所以概念相同,解决方案非常相似
标签: json scala parsing playframework playframework-2.4