D. Park
D. Park

Reputation: 23

Scala Play framework futures

I have 3 methods: a, b, and c. Method a has some logic and it calls method b. Method b makes an api call returning Future[String]. If the returned value from method b is a certain value, method c is called. Method c makes another api call returning another Future[String].

def a: String = Action { request =>
  val x = b("hello")
  x
}

def b(y: String): Future[String] = {
  val x = ws.url(url).post(y).map { response =>
    val value = response.body
    val z = if (response.body === "hi") response.body else c(response.body)
    z
  }
  x
}

def c(z: String): Future[String] = {
  val x = ws.url(url).post(z).map { response =>
    response.body
  }
  x
}

Something like the code above. Eventually I want to parse everything into a json object, but I'm having trouble getting the Futures as regular strings. I'm new to scala and would appreciate some input.

Upvotes: 0

Views: 341

Answers (1)

Lasf
Lasf

Reputation: 2582

You'll want something like this:

  def a: Action[AnyContent] = Action.async { _ =>
    b("hello").map(s => Ok(s))
  }

  def b(y: String): Future[String] = {
    ws.url(url).post(y).flatMap { response =>
      if (response.body == "hi") Future.successful(response.body) else c(response.body)
    }
  }

  def c(z: String): Future[String] = {
    ws.url(url).post(z).map { response =>
      response.body
    }
  }

A few things.

1) The type of your method a will be an Action[AnyContent], since you are creating a Play Action. It's common to see people omit the type of action methods and let the compiler figure it out. Note if your action is more sophisticated (e.g. it reads a JSON request body) then its type might be Action[something_else] (e.g. Action[JsValue] if you're using Play Json).

2) Because b returns a future, you need to create the Action using Action.async which takes a function of type Request => Future[Response] (before you were calling Action.apply which takes a function of type Request => Response).

3) In A, you need to map the String in the Future to a Response; I do this using Ok (i.e. HTTP 200), although of course you can use whatever's appropriate.

4) In b, flatMap is your friend, because c returns a Future[String] and thus you end up with a Future[Future[String]] when you use map... flatMap flattens that to a Future[String].

5) You need to wrap the first branch of your if statement in Future.successful, such that both branches return the same type, Future[String]. Future.successful just builds a Future that is already completed.

6) Finally, you don't need to declare values x, y and z; each expression resolves to its value, which really tidies things up.

Upvotes: 1

Related Questions