2015/07/21

[ScaVa->Scala] 好用的Scalaz - Validation

上一篇提到了Scalaz的Either,而今天要提到的是Either的好兄弟 - Validation

當我們在做Validation的時候,舉例來說,要驗證一個request所帶的參數是不是都是合法的,若這個request有多個參數,有時候我們會希望全部檢查過一遍,把所有有錯誤的地方全部回覆給request端,這樣才是比較有效率的構通模式。(才不會第一次只告訴你第一個參數錯,第二次你改好第一個欄位再來的時候,我才告訴你第二個參數其實也是錯的…)

下面的例子,是一個SearchUsersRequest,裡面寫好了一些檢查的條件,但是當你要用他的時候,你會發現很難去把每個exception都一個個抓出來,然後整理在一起之後組成一個回傳型態的物件再往外傳。


在這裡我們用Scalaz的Validation型態,再搭配上Nel(Non Empty List),來實作我們"通通都驗證"的例子。(使用Nel是為了要讓多個Validation可以透過Applicative的方式來輕鬆的結合在一起。
註:若沒有使用Nel的話,會發生這樣的錯誤 error: value |@| is not a member of scalaz.Validation[T,String]


從上面的例子可以看到
  • SearchUsersRequest裡頭的getXXX() 回傳的型態都是 ValidationNel[BaseException,T] (這裡的T有String, Int, List[String]...)
  • validate這個function使用了Scalaz所提供的Applicative syntax |@| 將ValidationNel[A,B]型態組合起來
  • TestApp的run裡面,建立了兩個case, reqFail和reqSuccess分別建立了 成功 和 有錯誤 的request object
  • validate()的回傳型態有點複雜…基本上就是ValidationNel的Non Empty List
    scalaz.Unapply[scalaz.Apply,scalaz.ValidationNel[BaseException,String]]{type M[X] = scalaz.ValidationNel[BaseException,X]; type A = String}#M[(String, Int, Int, List[String])]
  • 針對validate()的回傳值,為了比較清楚的知道如何使用,我這邊用pattern match的方式把Success和Failure分別取出,呈現可以如何操作
  • 因為Scalaz的Validation是Monad,基本上也是Applicative Functor,所以我們可以使用for, map...等的方式來操作他!

參考資料:



張貼留言

My World