2017-05-30 17 views
1

我正在構建一個API,它接受一個可變路徑參數或路由的動態部分,就像劇本文檔指定的一樣。Play2 - 驗證路由的動態部分

我想驗證這是爲了給客戶一個適當的迴應。

我有以下的路線設置

GET /:dynamic/all controller.method(dynamic: String)

dynamic參數有關該方法的整個API使用,多種方法,所以我想獲得某種可以接受的全球性驗證/白名單字符串。 (例如:"hello"/"hi"將被接受,並"noooway"將不被接受,並且我會返回一個404 not found作爲響應

我將優選喜歡我的控制器的方法,以不包含任何驗證,使得這將是真:

def method(dynamic: String): Action[AnyContent] = Action.async { _ => 
    //I already know "dynamic" is valid here. 
    Future.successful(Ok(Json.toJson(Map("status" -> "OK")))) 
} 

相反的:(原諒我javaisc-僞代碼)

def method(dynamic: String): Action[AnyContent] = Action.async { _ => 
    val valid = Helper.validate(dynamic) 
    if (!valid) return some result/response else 
    Future.successful(Ok(Json.toJson(Map("status" -> "OK")))) 
} 

回答

1

播放,您可以通過不同的方式來做到這一點

1 PathBindable

您可以實現PathBindable[T]任何類型T,使您從請求的路徑提取的值不是一個簡單的StringT

如果你準備改變dynamic類型(這將是有意義的,因爲它不應該是隨便一個字符串,但一個有效的),你可以做到以下幾點:

case class Validated(str: String) { 
    assert(Helper.validate(str)) 
} 

object Validated { 
    implicit val pathBindable = new PathBindable[Validated] { 
    val string = implicitly[PathBindable[String]] 
    override def bind(key: String, value: String): Either[String, Validated] = 
     string.bind(key, value).           // bind as if it were a string 
     right.filter(Helper.validate).getOrElse(Left("Invalid input")). // filter using your validation function, and give error message 
     right.map(Validated(_))           // encapsulate in your new type 

    override def unbind(key: String, value: Validated): String = 
     string.unbind(key, value.str) //unbind as if it were a string 
    } 
} 

注您需要爲反向路由實現unbind(獲取給定操作調用的路徑)。

現在,您只需要在您的路由器和您的控制器中用替換your.package.Validated

GET /:dynamic/all controller.method(dynamic: your.package.Validated) 

NB:如果你想使用你的類的簡單名稱,你需要將其導入您的build.sbt

(project in file("."). 
    enablePlugins(PlayScala). 
    settings(routesImport += "your.package.Validated") 

(二)行動組成

你也可以實現一個動作過濾器,以便在您的輸入需要驗證時使用:

case class ValidatedAction(input: String) extends ActionFilter[Request] { 
    override protected def filter[A](request: Request[A]): Future[Option[Result]] = Future.successful{ 
    if (Helper.validate(input)) None else Some(BadRequest("Invalid input")) 
    } 
} 

def method(dynamic: String) = (Action andThen ValidatedAction(dynamic)).async { 
    Future.successful(Ok) 
} 

async塊中的代碼將被執行僅當filter方法返回None,否則,它會返回指定Result(這裏,BadRequest("Invalid input")

+0

啊是的 - 非常感謝。我完全忘了考慮使用'ActionFilter'來做這種驗證。這對我來說似乎是一個很好的解決方案。同樣道具也適用於'PathBindable'解決方案。我很確定我遲早也會需要這個。 –