2

I want to call a second web service with the result from the first one.
Below is some code that highlights my intent.
By the way it compiles fine in IntelliJ(Probable a bug in the IDE).

  def get = {
    for {
      respA <- WS.url(url1).get
      id <- respA.body.split(",").take(2)
      respB <- WS.url(url2 + id).get // Here is a compile error
    } yield {
      getMyObjects(respB.xml)
    }
  }
  • respA = is a comma separated list with ids used in the next call.
  • respB = is an XML response that I parse in the yield method

The compile error Play Framework gives me:

type mismatch; 
found : scala.concurrent.Future[Seq[MyObject]] 
required: scala.collection.GenTraversableOnce[?]

I find the compile error strange.

  1. How can a Future of [Seq[MyObject]] exist at that line?
  2. It shouldn't be any different from the line two lines up that compiles?
Farmor
  • 8,604
  • 7
  • 34
  • 59

1 Answers1

4

WS.url(url1).get returns Future[Response] so all your generators in the for comprehension should be futures. In your code snippet, you are mixing Array[String] and Future[Response]. See Type Mismatch on Scala For Comprehension for some background on for comprehension.

So I would try something like this:

for {
  respA <- WS.url(url1).get
  ids = respA.body.split(",").take(2)
  responsesB <- Future.sequence(ids.map(id => WS.url(url2 + id).get))
} yield {
  responsesB.map(respB => getMyObjects(respB.xml))
}

So the types are:

respA: Response
ids: Array[String]
ids.map(id => WS.url(url2 + id).get): Array[Future[Response]]
Future.sequence(ids.map(id => WS.url(url2 + id).get)): Future[Array[Response]]
responsesB: Array[Response]

And the return type of the for comprehension is a Future of an array of whatever getMyObjects returns.

Note that if sequence does not work on Future[Array[_]] try to do ids = respA.body.split(",").toList.take(2).

Community
  • 1
  • 1
huynhjl
  • 40,642
  • 14
  • 99
  • 158