Play Framework 2.3(Scala)中的自定义JSON验证约束 [英] Custom JSON validation constraints in Play Framework 2.3 (Scala)
问题描述
我设法通过自定义约束实现表单验证,但现在我想对JSON数据执行相同的操作.
I managed to implement form validation with custom constraints, but now I want to do the same thing with JSON data.
如何将自定义验证规则应用于JSON解析器?
How can I apply custom validation rules to a JSON parser?
示例:客户端的POST请求包含一个用户名(username
),我不仅要确保此参数是一个非空文本,还要确保该用户实际上存在于数据库中.
Example: The client's POST request contains a user name (username
) and not only do I want to make sure that this parameter is a non-empty text, but also that this user actually exists in the database.
// 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
是一个字符串. 如何应用我的其他自定义验证规则,例如检查给定用户是否确实存在?这有可能吗?
That's as far as I get, but this only ensures that username
is a String. How do I apply my additional custom validation rule, e.g. to check if the given user really exists? Is this even possible?
当然,我可以将我的obj
放在操作的case success
部分中,并在那里执行其他检查,但这似乎并不十分优雅,因为那时我必须创建自己的错误消息,并且可以在某些情况下仅用户JsError.toFlatJson(error)
.搜索并尝试了几个小时后,我找不到任何示例.
Sure, I could take my obj
in the case success
section in the action and perform additional checks there, but this doesn't seem very elegant, because then I'd have to create my own error message and could only user JsError.toFlatJson(error)
for some cases. After searching and trying for hours I couldn't find any examples.
对于常规表格,我会使用类似这样的内容:
For regular forms I'd use something like this:
// 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提交怎么办?
But what if the data is submitted as JSON?
推荐答案
我想到的最简单的方法是使用Reads
中的filter
方法.
The simplest way I can think of would use the filter
method from Reads
.
假设我们有一些User
对象,它将确定用户名是否存在:
Let's say we have some User
object that will determine if the user name exists:
object User {
def findByName(name: String): Option[User] = ...
}
然后您可以像这样构造Reads
:
You could then construct your Reads
like this:
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
和fold
简化您的控制器功能:
Your controller function can be simplified using a json BodyParser
and 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[ExampleCaseClass]
中明确使用该Reads[String]
:
You could also create a separate Reads[String]
that will check if the user exists, and explicitly use that Reads[String]
within your 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 _)
这篇关于Play Framework 2.3(Scala)中的自定义JSON验证约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!