Reputation: 9734
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 true
– emptyObj
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.
Upvotes: 3
Views: 1091
Reputation: 9734
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 ;-)
Upvotes: 4