2016-04-14 7 views
0

Play 2.4プロジェクトで、私は3つのことをするアクションを作成しました。特定のヘッダが存在していることPlay 2.4 ActionBuilder/ActionFunction、BodyParsers、JSON

  1. チェック。そうでない場合は、HTTPエラーを返します。
  2. ヘッダー値を使用してユーザーを認証します(認証機能がそのアクションに渡されます)。 authが失敗した場合は、HTTPエラー
  3. を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と私が望む構成を書くことに成功しました。 私の質問は私の構成を改善する方法です。

おかげ
ジュール

+0

[再生:アクション構成を実装する方法](0120-18753)を参照してください。 – cchantep

+0

いいえ、このポストは単純なケースのみを説明しているためです私の質問に答えないでください。 –

+0

これは、 'BodyParser'を使ってアクションを構成しているので、コンセプトは同じで、解決方法は全く同じです – cchantep

答えて

0

よりむしろJsonRequestのための新しいActionBuilderを作るには、私は単にAuthentificationActionActionBuilderを使用し、それをJSON BodyParser渡します。このビルダーを使用して、任意のアクションを

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

を、意志Request[AnyContent]ではなくRequest[JsValue]になります。

+0

私はあなたの命題が非常に有用であるとは思っていません。私がそうするなら、コードは理解しにくいでしょう –

関連する問題