2015-04-13 2 views
2

У меня есть случай класса и сопутствующий объект:Scalaz проверки с Аргонавт

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) 

} 

Я хочу использовать Аргонавт, чтобы разобрать некоторые JSON и возвращать лицо или несколько ошибок, в виде списка. Поэтому мне нужно:

  1. Прочитайте JSON из строки и проверки строка правильно формируется
  2. Расшифруйте JSON в Person, или список строк ошибок.

Я хочу, чтобы возвращать ошибки в форме чего-то я могу превратиться в еще некоторые JSON, как:

{ 
    errors: ["Error1", "Error2"] 
} 

я впервые попытался использовать метод аргонавты decodeValidation, который возвращает Validation [String, X]. К сожалению, мне нужен список ошибок.

Любые предложения?

+0

Я не уверен, что есть хороший ответ, но вы всегда можете использовать 'decodeValidation' с' jdecode2L ((a: String, b: Int) => (a, b)) ("name", "age") ', чтобы получить кортеж, а затем переключиться на' ValidationNel'. –

+0

У вас есть пример? Извините, я действительно новичок в Scala. –

ответ

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) 
} 

И тогда я декодированием JSON в (String, Int) пару перед тем создание 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) 
    } 

И затем:

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

Обратите внимание, что это не аккумулировать ошибок в более сложных случаях-например, если значение поля name является числом, а age равно 1, вы получите только одну ошибку (name). Выполнение работы по накоплению ошибок в таких случаях будет значительно сложнее.

В связи с этим вы также увидите предупреждение об отказе от flatMap по адресу Validation, о котором вы можете вспомнить как напоминание о том, что накопление не произойдет через привязку. Вы можете сказать компилятору, что понимаете, импортируя scalaz.Validation.FlatMap._.

+0

Спасибо, это работает отлично. Я не получил предупреждение об отказе, я получил ошибку. Импорт FlatMap._ исправил его. –

+1

Как можно собирать ошибки? – eirirlar

Смежные вопросы