Let's say I have this model, in which I defined a custom case class IPAddress address with specific JSON formats. This class holds a String representation of an IPv4 and havs a validation in the Constructor that raises an IllegalArgumentException if the input string is not valid.
case class Node(id: UUID, name: String, ip: IPAddress)
case class IPAddress(s: String) {
val rx = """^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$""".r
require(rx.pattern.matcher(s).matches())
val ip = s
override def toString = ip
}
object JsonNodeFormat {
import play.api.libs.json.Json
implicit val midWrite: Writes[FMMid] = Writes {
(mid: FMMid) => JsString(mid.toString)
}
implicit val midRead: Reads[FMMid] = JsPath.read[String].map(FMMid(_))
implicit val NodeFormat = Json.format[Node]
}
Then I have my controller with an action that creates a new Node and write it in the database (in my case I'm using ReactiveMongo, but this is irrelevant)
class Nodes extends Controller with MongoController {
def collection: JSONCollection = db.collection[JSONCollection]("nodes")
import models._
import models.JsonNodeFormat._
def createTest = Action.async(parse.json) {
request =>
request.body.validate[Node].map {
node =>
collection.insert(node).map {
lastError =>
Created(s"Node Created")
}
}.getOrElse(Future.successful(BadRequest("invalid json")))
}
}
If make a request with valid json
{
"id": "0879d4be-78bb-4cc0-810b965b",
"ip": "192.168.0.10",
"name": "node1"
}
everything works fine. The object is correctly added to the db. I would like the controller return a BadRequest response when an invalid IP address is passed. On the contrary, if I pass a Json with an invalid IP address
{
"id": "0879d4be-78bb-4cc0-810b965b",
"ip": "192.168.0.foo",
"name": "node1"
}
it causes an internal server error with all the stack printed on the console (because nobody catches the constructor exception). I would like that when an invalid IPAddress is passed, the request.body.validate function fails and the execution falls in the getOrElse statement.
Also note that passing an invalid UUID doesn't generate an error but a BadRequest reply.
What's missing in my IPAddress class?
Try[String]
instead of String? You could wrap the ip validation so you can react in case you have a validation problem. - Carlos Vilchezrequire
and use another function likefindFirstIn
. Then you can process the Option[String] - Carlos Vilchez