Search code examples
scalascala-cats

How to cleanly validate function inputs and return a Future in Scala


I have a function (I removed the types because I'm more concerned about how to piece things together):

def func(opt1: Option, opt2: Option) = Future {
  for {
    o1 <- opt1
    o2 <- opt2
  } functionThatReturnsAFuture(o1, o2)
  Future.successful()
}

I'm trying to validate the options and then call my function that returns a future, but I don't know how to do this in idiomatic scala.

If I do this:

def func(opt1: Option, opt2: Option) = Future {
  for {
    o1 <- opt1
    o2 <- opt2
  } yield functionThatReturnsAFuture(o1, o2)
}

it's naturally going to return an Option[Future].

I could also do opt1.flatMap(opt2.map(functionThatReturnsAFuture)).sequence but this is still pretty ugly.

Is there any idiomatic scala (or scala + cats) way of doing validation like this and returning the Future?

Thanks!


Solution

  • You can solve this using Scala elegantly. In any case you need to handle case in which one of the options is none or both of the options are none.

    Return failed Future in case one or both of the values are none.

    case class NoneFoundException(msg: String) extends Exception(msg)
    
    def func(opt1: Option, opt2: Option) = {
     val result = 
      for {
        value1 <- opt1
        value2 <- opt2
      } yield someFutureReturningFunction(value1, value2)
    
     result.getOrElse {
      Future.failed(NoneFoundException("one or both of opt1, opt2 are none."))
     }
    
    }
    

    Communicate with types instead of exceptions

    sealed trait Result[+A]
    
    case class ReturnedValue[+A](value: A) extends Result[A]
    
    case class NoneFound extends Result[Nothing]
    
     def func(opt1: Option, opt2: Option) = {
      val result = 
       for {
         o1 <- opt1
         o2 <- opt2
       } functionThatReturnsAFuture(o1, o2).map(value => ReturnedValue(value))
    
      result.getOrElse {
       NoneFound
      }
    
    }
    

    Now the return type of the function is Future instead of Option of Future