簡體   English   中英

使用Scalaz驗證進行錯誤累積

[英]Error Accumulation with Scalaz Validation

我有一個復雜的JSON,它已存儲在數據庫中。 它的復雜性在“塊”中“隔離”,如下所示:

整個JSON:

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

在數據庫中,每個塊均被存儲和單獨處理:

持久塊

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

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

每個塊都有業務含義,因此,每個塊都映射到一個案例類。 我正在構建一個Play API,用於存儲,更新和檢索此JSON結構,並且我想驗證是否有人為了完整性而更改了它的數據。

我正在對每個塊進行檢索(解析和驗證),如下所示:

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

案例類:

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, ...)

在當前結構下,如果某些字段被更改且與定義的類型不匹配,則Play拋出此異常:

[NoSuchElementException:JsError.get]

因此,我想使用Scalaz和Validation建立一個累積的錯誤結構,以捕獲所有可能的解析和驗證錯誤。 我已經看到了 一點,因此我以這種方式編寫了驗證代碼:

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

請注意,我使用的是應用函子<*>因為Request具有20個字段(使用該語法的圓括號), |@| 適用函子僅適用於最多12個參數的案例類。

該代碼適用於幸福的道路,但是,當我修改某些字段時,Play會引發稍后描述的Execution Exception。

問題 :我想積累在解析每個塊時Play可以檢測到的所有可能的結構故障。 我怎樣才能做到這一點?

注意 :如果Shapeless在某種程度上與此有關,我願意使用它(我已經在使用它)。

如果多重驗證是向您的項目中添加Scalaz的唯一原因,那么為什么不考慮一種替代方案,它不需要您將Play項目適應於Scalaz強迫您解決問題的單子方式(這也許是一件好事,但是不一定(如果唯一的原因是多重驗證)。

而是考慮將標准Scala方法與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 }

這樣,您仍然可以對標准Scala集合進行操作,以檢索要進一步處理的故障列表。 同樣,此方法也不會限制塊的數量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM