Play: How to implement a conditional JSON validato

2019-04-10 17:26发布

My Play application has a JSON validator like this:

val validateAccount = (
  ((__ \ 'id).json.pickBranch) ~
  ((__ \ 'name).json.pickBranch) ~ // mandatory
  ((__ \ 'mobile).json.pickBranch or emptyObj) ~ // optional
  ...
).reduce

The validator above accepts JSON that contains at least an id and optionally a name. Is it possible to make a field mandatory depending on a condition? For instance, how do I make name mandatory when a condition is true and keep it optional when that condition is false?

def validateAccount(condition: Boolean) = (
  ((__ \ 'id).json.pickBranch) ~
  ((__ \ 'name).json.pickBranch if (condition) or emptyObj else ???) ~
  ((__ \ 'mobile).json.pickBranch or emptyObj) ~
  ...
).reduce

I want emptyObj if and only if codition is trueemptyObj just represents an empty node:

val emptyObj = __.json.put(Json.obj())

A [bad] solution could be something like this:

def validateAccount(condition: Boolean) = {
  (if (condition) {
    ((__ \ 'id).json.pickBranch) ~
    ((__ \ 'name).json.pickBranch) ~ // mandatory
    ((__ \ 'mobile).json.pickBranch or emptyObj) ~ // optional
    ...
  } else {
    ((__ \ 'id).json.pickBranch) ~
    ((__ \ 'name).json.pickBranch or emptyObj) ~ // now this is optional
    ((__ \ 'mobile).json.pickBranch or emptyObj) ~ // optional
    ...
  }).reduce
}

The reason I need conditional JSON validation is that when my REST api gets an insert request, the JSON has to be complete, while when it gets an update request, only the field to be updated should be provided.

1条回答
再贱就再见
2楼-- · 2019-04-10 18:25

OK... here is the solution:

package object typeExtensions {

  import play.api.libs.json._
  import play.api.libs.functional.syntax._

  implicit class ReadsExtensions(reads: Reads[JsObject]) extends AnyVal {

    def orEmpty = reads | __.put(Json.obj())
    def orEmptyIf(b: Boolean) = if (b) orEmpty else reads 
  }
}

object MyObject {

  def validateAccount(update: Boolean) = (
    ((__ \ 'id).json.pickBranch orEmptyIf update) ~ // can be empty only if update is true
    ((__ \ 'name).json.pickBranch orEmtpy) ~        // can be always empty
    ((__ \ 'mobile).json.pickBranch orEmpty) ~      // can be always empty
    ...
  ).reduce

  ...
}

I hope that helps ;-)

查看更多
登录 后发表回答