在 for-comp 中使用 EitherT-s 进行数据验证
Data validation with EitherT-s inside for-comp
考虑一下我要解决的问题的简化版本。这是我当前的实现。
case class Foo()
def addFoo(json: String): EitherT[Future, Exception, Long] = {
def parse(json: String): EitherT[Future, Exception, Foo] = ???
def validate(foo: Foo): EitherT[Future, Exception, Foo] = ???
def save(foo: Foo): EitherT[Future, Exception, Long] = ???
for {
foo <- parse(json)
_ <- validate(foo)
id <- save(foo)
} yield id
}
这感觉不对,因为尽管 validate
returns Exception
或 Foo
的 EitherT
,它只是执行验证和 returns 异常或未更改的 foo
值。所以,我们从不对 Either
的正确部分感兴趣,也从不使用它。有没有更好地对应 "validation" 语义的方法?
如果您不关心正确的值,您可以使用 Unit
而不是 Foo
,例如:
def validate(foo: Foo): EitherT[Future, Exception, Unit] = ???
您可以更改 validate
的类型签名以增加更多类型安全性:
def validate(foo: Foo): EitherT[Future, Exception, ValidFoo]
其中 ValidFoo
看起来像这样:
object ValidFoo {
def believeMeItsValid(raw: Foo): ValidFoo = new ValidFoo(raw)
}
class ValidFoo private (val foo: Foo)
和 save
将只接受经过验证的输入:
def save(foo: ValidFoo): EitherT[Future, Exception, Long]
这将强制您在保存输入之前验证输入并有助于防止 布尔盲目性。
考虑一下我要解决的问题的简化版本。这是我当前的实现。
case class Foo()
def addFoo(json: String): EitherT[Future, Exception, Long] = {
def parse(json: String): EitherT[Future, Exception, Foo] = ???
def validate(foo: Foo): EitherT[Future, Exception, Foo] = ???
def save(foo: Foo): EitherT[Future, Exception, Long] = ???
for {
foo <- parse(json)
_ <- validate(foo)
id <- save(foo)
} yield id
}
这感觉不对,因为尽管 validate
returns Exception
或 Foo
的 EitherT
,它只是执行验证和 returns 异常或未更改的 foo
值。所以,我们从不对 Either
的正确部分感兴趣,也从不使用它。有没有更好地对应 "validation" 语义的方法?
如果您不关心正确的值,您可以使用 Unit
而不是 Foo
,例如:
def validate(foo: Foo): EitherT[Future, Exception, Unit] = ???
您可以更改 validate
的类型签名以增加更多类型安全性:
def validate(foo: Foo): EitherT[Future, Exception, ValidFoo]
其中 ValidFoo
看起来像这样:
object ValidFoo {
def believeMeItsValid(raw: Foo): ValidFoo = new ValidFoo(raw)
}
class ValidFoo private (val foo: Foo)
和 save
将只接受经过验证的输入:
def save(foo: ValidFoo): EitherT[Future, Exception, Long]
这将强制您在保存输入之前验证输入并有助于防止 布尔盲目性。