scalaplayframeworkfuturews-client

play framewoerk & scala Future(s) chain. make it more pretty


I use WSClient to make rest requests. Each request return some Future.

as result I need to make request 1 and get some data. Then I need to make request 2 with data from result of request 1. Then I need to make request 3 with data from result of request 2. and so on

in my code it's looks like

def wsChain(data: Data): Future[NewData] = {
    getOne(data).flatMap(data2 => {
      getTwo(data2).flatMap(data3 => {
        getThree(data3).flatMap(data4 => {
          getFour(data4).map(result => foo(result))
        })
      })
    })
  }

It's very primitive sample without any modification of responses and requests. but I think that even it is difficult to read. I now about Await for Future, but it's anti-pattern

May be I can do this more pretty? Without N inner functions.


Solution

  • This is precisely the kind of situation that Scala's for-comprehensions are designed to help. You can replace your code with the following:

    def wsChain(data: Data): Future[NewData] = for {
      data2  <- getOne(data)
      data3  <- getTwo(data2)
      data4  <- getThree(data3)
      result <- getFour(data4)
    } yield foo(result)
    

    …and it will be desugared by the compiler to exactly the same thing. You can read more about for-comprehensions here, but in short, any time you find yourself with a long chain of flatMap calls (and maybe a map at the end), you should consider rewriting them as a for-comprehension, which makes your code more readable by collapsing the deep nesting.