使用Argonaut进行Scalaz验证

Dom*_*mra 2 json scala scalaz argonaut

我有一个案例类和伴侣对象:

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)

}
Run Code Online (Sandbox Code Playgroud)

我想使用Argonaut解析一些JSON并返回一个Person或一些错误,作为一个列表.所以我需要:

  1. 从字符串中读取JSON,并验证字符串是否正确形成
  2. 将JSON解码为Person或错误字符串列表.

我希望以某种形式返回错误,我可以将其变成更多JSON,如:

{
  errors: ["Error1", "Error2"]
}
Run Code Online (Sandbox Code Playgroud)

我首先尝试使用Argonauts decodeValidation方法,该方法返回Validation [String,X].不幸的是,我需要一个错误列表.

有什么建议?

Tra*_*own 5

我正在添加这个作为答案,因为这是我如何解决问题,但我还没有与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)
}
Run Code Online (Sandbox Code Playgroud)

然后我(String, Int)在创建之前将JSON解码为一对Person:

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)
  }
Run Code Online (Sandbox Code Playgroud)

然后:

scala> println(decodePerson("""{ "name": "", "age": 1 }"""))
Failure(NonEmptyList(Name too short, Age is under 18))
Run Code Online (Sandbox Code Playgroud)

请注意,这不会积聚在更复杂的情况下的错误,例如,如果值name字段是一个数字,age1,你只能得到一个错误(name一个).在这样的情况下进行错误累积工作会相当复杂.

相关地,您还会看到有关flatMapon 的弃用警告Validation,您可以将其视为提醒,即不会在绑定中发生累积.您可以通过导入告诉编译器您理解scalaz.Validation.FlatMap._.