Reputation: 105
Consider a simplified version of the problem that I'm trying to solve. Here's my current implementation.
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
}
This doesn't feel right because, although validate
returns an EitherT
of Exception
or Foo
, it just performs the validation and returns either an exception or an unchanged foo
value. So, we are never interested in the right part of the Either
and never use it. Is there any approach that corresponds better to the "validation" semantics?
Upvotes: 2
Views: 75
Reputation: 4017
You can change type signature of validate
to add more type safety:
def validate(foo: Foo): EitherT[Future, Exception, ValidFoo]
where ValidFoo
looks like that:
object ValidFoo {
def believeMeItsValid(raw: Foo): ValidFoo = new ValidFoo(raw)
}
class ValidFoo private (val foo: Foo)
and save
would accept only validated input:
def save(foo: ValidFoo): EitherT[Future, Exception, Long]
This would force you to validate input before saving it and help against boolean blindness.
Upvotes: 2
Reputation: 22635
If you don't care about right value you can just use Unit
instead of Foo
, like:
def validate(foo: Foo): EitherT[Future, Exception, Unit] = ???
Upvotes: 1