使用 Argonaut 进行 Scalaz 验证
Scalaz validation with Argonaut
我有一个案例 class 和伴随对象:
case class Person private(name: String, age: Int)
object Person {
def validAge(age: Int) = {
if (age > 18) age.successNel else "Age is under 18".failureNel
}
def validName(name: String) = {
name.successNel
}
def create(name: String, age: Int) = (validAge(age) |@| validName(name))(Person.apply)
}
我想使用 Argonaut 来解析一些 JSON 和 return 一个人或一些错误,作为一个列表。所以我需要:
- 从字符串中读取 JSON,并验证字符串的格式是否正确
- 将 JSON 解码为 Person 或错误字符串列表。
我想 return 以我可以变成更多 JSON 形式的错误,例如:
{
errors: ["Error1", "Error2"]
}
我首先尝试使用 Argonauts decodeValidation 方法,它 return 是一个 Validation[String, X]。不幸的是,我需要一个错误列表。
有什么建议吗?
我添加这个作为答案,因为这是我解决问题的方式,但我已经有一段时间没有密切关注 Argonaut 的开发了,我很乐意听说有更好的方法。首先是设置,它修复了您的一些小问题,并添加了名称有效性的条件以使后面的示例更有趣:
import scalaz._, Scalaz._
case class Person private(name: String, age: Int)
object Person {
def validAge(age: Int): ValidationNel[String, Int] =
if (age > 18) age.successNel else "Age is under 18".failureNel
def validName(name: String): ValidationNel[String, String] =
if (name.size >= 3) name.successNel else "Name too short".failureNel
def create(name: String, age: Int) =
(validName(name) |@| validAge(age))(Person.apply)
}
然后我在创建 Person
:
之前将 JSON 解码为 (String, Int)
对
import argonaut._, Argonaut._
def decodePerson(in: String): ValidationNel[String, Person] =
Parse.decodeValidation(in)(
jdecode2L((a: String, b: Int) => (a, b)
)("name", "age")).toValidationNel.flatMap {
case (name, age) => Person.create(name, age)
}
然后:
scala> println(decodePerson("""{ "name": "", "age": 1 }"""))
Failure(NonEmptyList(Name too short, Age is under 18))
请注意,这不会在更复杂的情况下累积错误,例如如果 name
字段的值是一个数字并且 age
是 1
,您只会得到一个错误(name
一个)。在这种情况下使错误累积起作用会复杂得多。
与此相关,您还会在 Validation
上看到关于 flatMap
的弃用警告,您可以将其视为一个提醒,表明绑定不会发生累积。你可以通过导入 scalaz.Validation.FlatMap._
.
告诉编译器你理解了
我有一个案例 class 和伴随对象:
case class Person private(name: String, age: Int)
object Person {
def validAge(age: Int) = {
if (age > 18) age.successNel else "Age is under 18".failureNel
}
def validName(name: String) = {
name.successNel
}
def create(name: String, age: Int) = (validAge(age) |@| validName(name))(Person.apply)
}
我想使用 Argonaut 来解析一些 JSON 和 return 一个人或一些错误,作为一个列表。所以我需要:
- 从字符串中读取 JSON,并验证字符串的格式是否正确
- 将 JSON 解码为 Person 或错误字符串列表。
我想 return 以我可以变成更多 JSON 形式的错误,例如:
{
errors: ["Error1", "Error2"]
}
我首先尝试使用 Argonauts decodeValidation 方法,它 return 是一个 Validation[String, X]。不幸的是,我需要一个错误列表。
有什么建议吗?
我添加这个作为答案,因为这是我解决问题的方式,但我已经有一段时间没有密切关注 Argonaut 的开发了,我很乐意听说有更好的方法。首先是设置,它修复了您的一些小问题,并添加了名称有效性的条件以使后面的示例更有趣:
import scalaz._, Scalaz._
case class Person private(name: String, age: Int)
object Person {
def validAge(age: Int): ValidationNel[String, Int] =
if (age > 18) age.successNel else "Age is under 18".failureNel
def validName(name: String): ValidationNel[String, String] =
if (name.size >= 3) name.successNel else "Name too short".failureNel
def create(name: String, age: Int) =
(validName(name) |@| validAge(age))(Person.apply)
}
然后我在创建 Person
:
(String, Int)
对
import argonaut._, Argonaut._
def decodePerson(in: String): ValidationNel[String, Person] =
Parse.decodeValidation(in)(
jdecode2L((a: String, b: Int) => (a, b)
)("name", "age")).toValidationNel.flatMap {
case (name, age) => Person.create(name, age)
}
然后:
scala> println(decodePerson("""{ "name": "", "age": 1 }"""))
Failure(NonEmptyList(Name too short, Age is under 18))
请注意,这不会在更复杂的情况下累积错误,例如如果 name
字段的值是一个数字并且 age
是 1
,您只会得到一个错误(name
一个)。在这种情况下使错误累积起作用会复杂得多。
与此相关,您还会在 Validation
上看到关于 flatMap
的弃用警告,您可以将其视为一个提醒,表明绑定不会发生累积。你可以通过导入 scalaz.Validation.FlatMap._
.