1

I have a complex JSON that it's persisted in a database. It's complexity is "segregated" in "blocks", as follows:

Entire JSON:

{
    "block1" : {
        "param1" : "val1",
        "param2" : "val2"
    },
    "block2" : {
        "param3" : "val3",
        "param4" : "val4"
    },
    ...
}

In the database, every block is stored and treated individually:

Persisted Blocks

"block1" : {
    "param1" : "val1",
    "param2" : "val2"
}

"block2" : {
    "param3" : "val3",
    "param4" : "val4"
}

Every block has a business meaning, so, every one it's mapped to a case-class. I'm building a Play API that stores, updates and retrieves this JSON Structure and i want to validate if someone altered it's data for the sake of integrity.

I'm doing the retrieval (parsing and validation) of every block as follows:

val block1 = Json.parse(block1).validate[Block1].get
val block2 = Json.parse(block2).validate[Block2].get
...

The case-classes:

trait Block
sealed case class Block1 (param1: String, param2: String, ...) extends Block
sealed case class Block2 (param3: String, param4: String, ...) extends Block
sealed case class Request (block1: Block1, block2: Block2, ...)

With the current structure, if some field is altered and doesn't match with the defined type for it Play throws this exception:

[NoSuchElementException: JsError.get]

So, i want to build an accumulative error structure with Scalaz and Validation that catch all possible parsing and validation errors. I have seen this and this so i've coded the validation this way:

def build(block1: String, block2: String, ...): Validation[NonEmptyList[String], Request] = {
    val block1 = Option(Json.parse(block1).validate[Block1].get).toSuccess("Error").toValidationNel
    val block2 = Option(Json.parse(block2).validate[Block2].get).toSuccess("Error").toValidationNel
    ...

    val request = (Request.apply _).curried

    blockn <*> (... <*> (... <*> (...<*> (block2 <*> (block1 map request)))))   
}

Note that i'm using the applicative functor <*> because Request has 20 fields (building that is a parentheses-mess with that syntax), |@| applicative functor only applies for case classes up to 12 parameters.

That code works for the happy path, but, when i modify some field Play throws the Execution Exception later described.

Question: I want to accumulate all possible structure faults that Play can detect while parsing every block. How can i do that?

Note: If in some way Shapeless has something to do with this i'm open to use it (i'm already using it).

Community
  • 1
  • 1
Alejandro Echeverri
  • 1,328
  • 2
  • 19
  • 32

1 Answers1

2

If multi-validation is the only reason for adding Scalaz to your project then why not consider an alternative which will not require you adapt your Play project to the monadic way in which Scalaz forces you to solve problems (which might be a good thing, but not necessarily if the only reason for that is multi-validation).

Instead consider using a standard Scala approach with scala.util.Try:

val block1 = Try(Json.parse(block1).validate[Block1].get)
val block2 = Try(Json.parse(block2).validate[Block2].get)
...

val allBlocks : List[Try[Block]] = List(block1, block2, ...)
val failures : List[Failure[Block]] = allBlocks.collect { case f : Failure[Block] => f }

This way you can still operate on standard scala collections to retrieve the list of failures to be processed further. Also this approach does not constrain you in terms of number of blocks.

Norbert Radyk
  • 2,608
  • 20
  • 24
  • Why negative please? Is this not an answer to 'Question: I want to accumulate all possible structure faults that Play can detect while parsing every block. How can i do that?'? – Norbert Radyk Aug 31 '15 at 14:27
  • I'm not the one that downvoted your answer. Actually i think that it's totally valid your thought about the use of standard Try instead of Scalaz validation, but i have a question about that: why do you say that "... if the only reason for that is multi-validation"? Is there a "potential misuse" of Scalaz if i only use Validation? – Alejandro Echeverri Aug 31 '15 at 14:41
  • I've seen quite a few projects where scalaz has been used primarily for its validation capabilities, so I guess it can't be classified as 'misuse'. The problem here is with a steep learning curve and the lack of good documentation. Scalaz is huge and incredibly powerful and decision to ingrain it into a system should be a conscious one, considering future code maintenance and how easy it is to onboard new developers. Also it promotes a certain style of coding and constructs which is not necessarily what you would do in standard Scala. Therefore my answer, which provides an alternative :) – Norbert Radyk Aug 31 '15 at 15:17
  • Well, i think that i've "over-engineered" the solution to my problem, then. I'll try your approach – Alejandro Echeverri Aug 31 '15 at 15:23