Play 2.4プロジェクトで、私は3つのことをするアクションを作成しました。特定のヘッダが存在していることPlay 2.4 ActionBuilder/ActionFunction、BodyParsers、JSON
- チェック。そうでない場合は、HTTPエラーを返します。
- ヘッダー値を使用してユーザーを認証します(認証機能がそのアクションに渡されます)。 authが失敗した場合は、HTTPエラー
- をJSON本体をケースクラスに解析し、Actionブロックコードに渡します。 https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition
が、より具体的には、私が望んでいた最終的な結果は、ここで説明されています:私はこれを書くことに成功した https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition#Putting-it-all-together
はそれを行うには、私がプレイアクション組成mecanismは、このページで説明使用しました:
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と私が望む構成を書くことに成功しました。 私の質問は私の構成を改善する方法です。
おかげ
ジュール
[再生:アクション構成を実装する方法](0120-18753)を参照してください。 – cchantep
いいえ、このポストは単純なケースのみを説明しているためです私の質問に答えないでください。 –
これは、 'BodyParser'を使ってアクションを構成しているので、コンセプトは同じで、解決方法は全く同じです – cchantep