Play Framework 2.3(Scala)中的自定义JSON验证约束 [英] Custom JSON validation constraints in Play Framework 2.3 (Scala)

查看:143
本文介绍了Play Framework 2.3(Scala)中的自定义JSON验证约束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我设法通过自定义约束实现表单验证,但现在我想对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 BodyParserfold简化您的控制器功能:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆