Reputation: 267040
I have a fairly complicated form that lets the user select some drop down values and input text in input boxes etc.
The form is essentially a 'Advanced Search' type form.
def search = Action(parse.json) { request =>
val sR = request.body.validate[SearchRequest]
sR.fold(
errors => {
BadRequest(Json.obj("status" -> "KO", "message" -> JsError.toJson(errors)))
},
searchRequest => {
Logger.debug(s"searchRequest is $searchRequest")
val sr = SearchResults(10)
Ok(Json.toJson(sr))
}
)
}
Say I have a drop down list that has the following values:
IsGreaThan
IsLessThan
EqualTo
My SearchRequest looks like:
case class SearchRequest(operator: String)
But I don't want the user to potentially send bad data i.e. a string other than 'IsGreaterThan', 'IsLessThan' etc.
How can I make it strongly typed when the JSON binds to the SearchRequest object?
Upvotes: 1
Views: 374
Reputation: 10007
I think what you're looking for is a Reads
instance for an enumerated type; i.e.:
Declare a specific SearchOperator
enum:
object SearchOperator extends Enumeration {
type SearchOperator = Value
val IsGreaThan = Value("IsGreaThan")
val IsLessThan = Value("IsLessThan")
val EqualTo = Value("EqualTo")
}
Use it in the SearchRequest
case class:
case class SearchRequest(lhs: Int, operator: SearchOperator, rhs:Int)
Define how to read it:
object SearchRequestJson {
implicit val soReads = Reads.enumNameReads(SearchOperator)
implicit val srReads = Json.reads[SearchRequest]
}
The key thing being the Reads.enumNameReads
function which was added to Play in version 2.4, and saves a heap of boilerplate for your situation.
Now, if I submit an illegal value as part of the search request:
{ "lhs": 42, "operator": "NotEqualTo", "rhs": 44 }
I get a:
JsError(
List(
(/operator, List(
ValidationError(
List(error.expected.enumstring),
WrappedArray()
)
))
)
)
Upvotes: 2