2016-04-14 2 views
0

In einem Play 2.4-Projekt habe ich eine Action erstellt, die drei Dinge erledigt.Abspielen 2.4 ActionBuilder/ActionFunction, BodyParsers und JSON

  1. überprüfen Sie, ob eine bestimmte Kopfzeile vorhanden ist. Wenn nicht, wird ein HTTP-Fehler zurückgegeben.
  2. 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
  3. 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

+0

Mögliches Duplikat von [Play: So implementieren Sie die Aktionszusammensetzung] (http://stackoverflow.com/questions/25105558/play-how-to-implement-action-composition) – cchantep

+0

Nein, weil dieser Beitrag nur einen einfachen Fall erklärt von der Aktionszusammensetzung und antworte nicht auf meine Fragen. –

+0

Es ist das Erstellen von Aktionen mit 'BodyParser', also sind die Konzepte die gleichen, die Lösungen ziemlich ähnlich – cchantep

Antwort

0

vielmehr ein neues ActionBuilder für eine JsonRequest als zu machen, würde ich einfach die AuthentificationActionActionBuilder verwenden und eine json passieren BodyParser:

AuthentificationAction(parse.json) { 
    request => // Note that the request has type Request[JsValue] 
    doStuffWithJson(request.body) 
} 

Alle diesen Builder Aktion verwendet wird, wird erhalten Sie eine Request[JsValue] anstelle einer Request[AnyContent].

+0

Ich finde Ihren Vorschlag nicht sehr nützlich. Der Code wird weniger verständlich, wenn ich das tue –