Soroush Mirzaei
Soroush Mirzaei

Reputation: 926

Scala recursive API calls to get all the results

I'm pretty new to Scala, and what I'm trying to achieve is to make enough calls to an API with different offset until I get all the results.

Here's a simplified version of what I have, and I was wondering if there is a more idiomatic Scala way to do it. (The code sample might not be 100% accurate, it's just something I put up as an example)

def getProducts(
                 limit: Int = 50,
                 offset: Int = 0,
                 otherProducts: Seq[Product] = Seq()): Future[Seq[Product]] = {

  val eventualResponse: Future[ApiResponse] = apiService.getProducts(limit, offset)

  val results: Future[Seq[Product]] = eventualResponse.flatMap { response =>

    if (response.isComplete) {
      logger.info("Got every product!")
      Future.successful(response.products ++ otherProducts)
    } else {
      logger.info("Need to fetch more data...")

      val newOffset = offset + limit
      getProducts(limit, newOffset, otherProducts ++ response.products)
    }
  }

  results
}

Passing the otherProducts parameter just doesn't feel right :P

Thanks in advance for any suggestions :)

Upvotes: 4

Views: 290

Answers (1)

dmitry
dmitry

Reputation: 5039

It seems you've exposed the tail recursion implementation, which is a bit like implementation detail in functional programming.

As for me, I typically wrap such functions into an external call without accumulator parameter (otherProducts):

def getProducts(limit: Int = 50, offset: Int = 0): Future[Seq[Product]] = {
   def loop(limit: Int = 50,
             offset: Int = 0,
             acc: Seq[Product] = Seq()): Future[Seq[Product]] = ... your code with tail recursion...

   loop(limit, offset)
}

But it is just a matter of taste, and of course it is valid if otherProducts is just a fancy name for tailrec accumulator.

Upvotes: 5

Related Questions