Play2 - 验证路线的动态部分
Play2 - validation of dynamic part of route(s)
我正在构建一个 API,它采用可变路径参数或路线的动态部分,正如播放文档所指定的那样。
我想验证一下,以便给客户一个正确的回应。
我有以下路线设置
GET /:dynamic/all controller.method(dynamic: String)
该方法的 dynamic
参数在 API 中用于多种方法,因此我想获得某种全局 validation/whitelist 可接受的字符串。 (例如:"hello"/"hi"
会被接受,"noooway"
不会被接受,我会 return 一个 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-psuedo-code)
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"))))
}
Play 允许您通过不同的方式做到这一点。
1. PathBindable
你可以为任何类型T
实现一个PathBindable[T]
,这样你从请求路径中提取的值就不是简单的String
而是一个T
.
如果您准备更改 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
(获取给定操作调用的路径)。
现在,您只需将路由器和控制器中的 String
替换为 your.package.Validated
。
GET /:dynamic/all controller.method(dynamic: your.package.Validated)
注意:如果你想使用你的class的简单名称,你需要在你的build.sbt
中导入它:
(project in file(".").
enablePlugins(PlayScala).
settings(routesImport += "your.package.Validated")
2。动作组合
您还可以实施一个操作过滤器,以便在需要验证您的输入时使用:
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)
}
只有filter
方法returns None
才会执行async
块内的代码,否则会return指定的Result
(这里,BadRequest("Invalid input")
.
我正在构建一个 API,它采用可变路径参数或路线的动态部分,正如播放文档所指定的那样。
我想验证一下,以便给客户一个正确的回应。
我有以下路线设置
GET /:dynamic/all controller.method(dynamic: String)
该方法的 dynamic
参数在 API 中用于多种方法,因此我想获得某种全局 validation/whitelist 可接受的字符串。 (例如:"hello"/"hi"
会被接受,"noooway"
不会被接受,我会 return 一个 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-psuedo-code)
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"))))
}
Play 允许您通过不同的方式做到这一点。
1. PathBindable
你可以为任何类型T
实现一个PathBindable[T]
,这样你从请求路径中提取的值就不是简单的String
而是一个T
.
如果您准备更改 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
(获取给定操作调用的路径)。
现在,您只需将路由器和控制器中的 String
替换为 your.package.Validated
。
GET /:dynamic/all controller.method(dynamic: your.package.Validated)
注意:如果你想使用你的class的简单名称,你需要在你的build.sbt
中导入它:
(project in file(".").
enablePlugins(PlayScala).
settings(routesImport += "your.package.Validated")
2。动作组合
您还可以实施一个操作过滤器,以便在需要验证您的输入时使用:
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)
}
只有filter
方法returns None
才会执行async
块内的代码,否则会return指定的Result
(这里,BadRequest("Invalid input")
.