Andrey Tararaksin
Andrey Tararaksin

Reputation: 105

Data validation with EitherT-s inside for-comp

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

Answers (2)

simpadjo
simpadjo

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

Krzysztof Atłasik
Krzysztof Atłasik

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

Related Questions