In einem Play 2.4-Projekt habe ich eine Action erstellt, die drei Dinge erledigt.Abspielen 2.4 ActionBuilder/ActionFunction, BodyParsers und JSON
- überprüfen Sie, ob eine bestimmte Kopfzeile vorhanden ist. Wenn nicht, wird ein HTTP-Fehler zurückgegeben.
- Verwenden Sie den Header-Wert, um den Benutzer zu authentifizieren (an diese Aktion wird eine Authentifizierungsfunktion übergeben). Wenn die Authentifizierung fehlschlägt, wird ein HTTP-Fehler
- den JSON-Text zu einer Fallklasse analysiert und an den Aktionsblockcode übergeben.
, das zu tun, habe ich die Play-Action-Zusammensetzung mecanism auf dieser Seite erklären: https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition
aber genauer gesagt, das Endergebnis wollte ich wird hier erklärt: https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition#Putting-it-all-together
ich schreiben konnte:
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))
)
}
}
}
es scheint gut zu funktionieren, aber es ist nicht perfekt, weil ich Kraft ist den Any
Typen in den case class ParsedJsonRequest[A](parsed: Any, request: Request[A])
zu verwenden, weil es tha scheint t Ich kann das nicht: case class ParsedJsonRequest[T, A](parsed: T, request: Request[A])
Ist es möglich, das zu tun? Glaubst du, ich kann meine Lösung verbessern? Wie ?
Meine Frage ist nicht, wie man Aktion Zusammensetzung. Ich verstehe, wie es funktioniert und mir ist es gelungen, meine ActionBuilder und meine gesuchte Komposition zu schreiben. Meine Frage ist, wie ich meine Komposition verbessern kann.
Dank
Jules
Mögliches Duplikat von [Play: So implementieren Sie die Aktionszusammensetzung] (http://stackoverflow.com/questions/25105558/play-how-to-implement-action-composition) – cchantep
Nein, weil dieser Beitrag nur einen einfachen Fall erklärt von der Aktionszusammensetzung und antworte nicht auf meine Fragen. –
Es ist das Erstellen von Aktionen mit 'BodyParser', also sind die Konzepte die gleichen, die Lösungen ziemlich ähnlich – cchantep