Предположим, у меня есть эта модель, в которой я определил адрес IPAddress с индивидуальным кодом класса с определенными форматами JSON. Этот класс содержит строковое представление IPv4 и содержит проверку в конструкторе, которая вызывает исключение IllegalArgumentException, если строка ввода недопустима.Play2/Scala Пользовательская проверка поля JSON
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]
}
Тогда у меня есть контроллер с действием, которое создает новый узел и запись в базе данных (в моем случае я использую ReactiveMongo, но это не имеет значения)
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")))
}
}
Если марка запрос с действительным json
{
"id": "0879d4be-78bb-4cc0-810b965b",
"ip": "192.168.0.10",
"name": "node1"
}
все работает нормально. Объект правильно добавлен в db. Я бы хотел, чтобы контроллер возвращал ответ BadRequest при передаче недопустимого IP-адреса. Наоборот, если я прохожу JSon с некорректным IP адрес
{
"id": "0879d4be-78bb-4cc0-810b965b",
"ip": "192.168.0.foo",
"name": "node1"
}
это вызывает внутреннюю ошибку сервера со всеми стека, напечатанной на консоли (потому что никто не ловит исключение конструктора). Я хотел бы, чтобы при передаче недопустимого IPAddress функция request.body.validate завершилась неудачно, и выполнение попало в оператор getOrElse.
Также обратите внимание, что передача недопустимого UUID не генерирует ошибку, а ответ BadRequest.
Что отсутствует в классе IPAddress?
Вы думаете о возврате 'Try [String]' вместо String? Вы можете обернуть проверку ip, чтобы вы могли реагировать, если у вас есть проблема проверки. –
Да, это абсолютно решение. Но я хотел потребовать к body.validate всю работу, так что мне не понадобится еще один блок кода и, следовательно, дополнительный уровень вложенности. Мне просто интересно, потому что все работает так, как ожидалось, с UUID. – tano
Play дает вам возможность решить, как ответить на конкретное исключение. Вы можете переопределить определение функции onError внутри объекта Global. Там вы можете получить исключение, и вы сможете вернуть код BadRequest. –