我设法使用自定义约束实现表单验证,但现在我想对 JSON 数据做同样的事情。
如何将自定义验证规则应用于 JSON 解析器?
示例:客户端的 POST 请求包含一个用户名( username
),我不仅要确保此参数是非空文本,还要确保该用户确实存在于数据库中。
// In the controller...
def postNew = Action { implicit request =>
request.body.asJson.map { json =>
json.validate[ExampleCaseClass] match {
case success: JsSuccess[ExampleCaseClass] =>
val obj: ExampleCaseClass = success.get
// ...do something with obj...
Ok("ok")
case error: JsError =>
BadRequest(JsError.toFlatJson(error))
}
} getOrElse(BadRequest(Json.obj("msg" -> "JSON request expected")))
}
// In ExampleCaseClass.scala...
case class ExampleCaseClass(username: String, somethingElse: String)
object ExampleCaseClass {
// That's what I would use for a form:
val userCheck: Mapping[String] = nonEmptyText.verifying(userExistsConstraint)
implicit val exampleReads: Reads[ExampleCaseClass] = (
(JsPath \ "username").read[String] and
(JsPath \ "somethingElse").read[String]
)(ExampleCaseClass.apply _)
}
就我所知,但这只能确保
username
是一个字符串。 如何应用我的附加自定义验证规则 ,例如检查给定的用户是否真的存在?这甚至可能吗?当然,我可以带我的
obj
在 case success
部分并在那里执行其他检查,但这似乎不是很优雅,因为那样我必须创建自己的错误消息并且只能使用 JsError.toFlatJson(error)
对于某些情况。经过几个小时的搜索和尝试,我找不到任何例子。对于常规形式,我会使用这样的东西:
// In the controller object...
val userValidConstraint: Constraint[String] = Constraint("constraints.uservalid")({ username =>
if (User.find(username).isDefined) {
Valid
} else {
val errors = Seq(ValidationError("User does not exist"))
Invalid(errors)
}
})
val userCheck: Mapping[String] = nonEmptyText.verifying(userValidConstraint)
val exampleForm = Form(
mapping(
"username" -> userCheck
// ...and maybe some more fields...
)(ExampleCaseClass.apply)(ExampleCaseClass.unapply)
)
// In the controller's action method...
exampleForm.bindFromRequest.fold(
formWithErrors => {
BadRequest("Example error message")
},
formData => {
// do something
Ok("Valid!")
}
)
但是如果数据以 JSON 格式提交呢?
最佳答案
我能想到的最简单的方法是使用 filter
方法来自 Reads
.
假设我们有一些 User
将确定用户名是否存在的对象:
object User {
def findByName(name: String): Option[User] = ...
}
然后你可以构建你的
Reads
像这样:import play.api.libs.json._
import play.api.libs.functional.syntax._
import play.api.data.validation._
case class ExampleCaseClass(username: String, somethingElse: String)
object ExampleCaseClass {
implicit val exampleReads: Reads[ExampleCaseClass] = (
(JsPath \ "username").read[String].filter(ValidationError("User does not exist."))(findByName(_).isDefined) and
(JsPath \ "somethingElse").read[String]
)(ExampleCaseClass.apply _)
}
可以使用 json
BodyParser
简化您的 Controller 功能和 fold
:def postNew = Action(parse.json) { implicit request =>
request.body.validate[ExampleCaseClass].fold(
error => BadRequest(JsError.toFlatJson(error)),
obj => {
// Do something with the validated object..
}
)
}
您也可以创建一个单独的
Reads[String]
这将检查用户是否存在,并明确使用该 Reads[String]
在您的 Reads[ExampleCaseClass]
内:val userValidate = Reads.StringReads.filter(ValidationError("User does not exist."))(findByName(_).isDefined)
implicit val exampleReads: Reads[ExampleCaseClass] = (
(JsPath \ "username").read[String](userValidate) and
(JsPath \ "somethingElse").read[String]
)(ExampleCaseClass.apply _)
关于json - Play Framework 2.3 (Scala) 中的自定义 JSON 验证约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26317186/