2

I need to perform a single synchronous HTTP POST call: create an HTTP Post request with some data, connect to the server, send the request, receive the response, and close the connection. It is important to release all resources used to do this call.

Now I am doing it in Java with Apache Http Client. How can I do it with Scala dispatch library ?

Michael
  • 41,026
  • 70
  • 193
  • 341

2 Answers2

8

Something like this should work (haven't tested it though)

import dispatch._, Defaults._
import scala.concurrent.Future
import scala.concurrent.duration._

def postSync(path: String, params: Map[String, Any] = Map.empty): Either[java.lang.Throwable, String] = {
  val r = url(path).POST << params
  val future = Http(r OK as.String).either
  Await.result(future, 10.seconds)
}

(I'm using https://github.com/dispatch/reboot for this example)

You explicitly wait for the result of the future, which is either a String or an exception.

And use it like

postSync("http://api.example.com/a/resource", Map("param1" -> "foo") match {
  case Right(res) => println(s"Success! Result was $res")
  case Left(e) => println(s"Woops, something went wrong: ${e.getMessage}")
}
Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
  • Thank you. What resources does this code use ? Does the `future` use a JVM thread pool ? Does the code close the connection after reading the response ? – Michael Aug 18 '14 at 10:17
  • the future uses an implicit `ExecutionContext` which is imported by `Defaults._`. The default implementation usually makes use of a fork-join thread pool, but it actually depends on how `dispatch` configures it. You can check it out in the implementation, or - if you prefer - you can supply a custom-configured `ExecutionContext` yourself and skip the `Defaults._` import. Concerning the connection, `dispatch` should close it once the response has been received. – Gabriele Petronella Aug 18 '14 at 10:21
  • Great ! Thanks again. Can I make the future _not_ take a thread ? Looks like the future _always_ requires an additional thread (and since this code waits for the future in the current thread, it requires at least 2 threads i/o one thread in sync. case). – Michael Aug 18 '14 at 10:25
  • I'm afraid that's not possible with the `dispatch/reboot` library, since the `HttpExecutor` it defines explicitly requires an `AsyncHttpClient` – Gabriele Petronella Aug 18 '14 at 10:33
  • Thanks. Are you aware of any _synchronous_ HTTP client library for Scala ? – Michael Aug 18 '14 at 10:34
  • @Michael you could look at the original `dispatch` library (also referred to as `dispatch-classic`). I'm not familiar with it, but it might offer a synchronous Http executor. – Gabriele Petronella Aug 18 '14 at 10:36
0

We all know that Scala's important feature is async. So there are lots of solutions to tell people how to do HTTP CALL ASYNC. For example, dispatch is the async http library. But here we care about how to implement sync http call by scala. I use a trick to do it.

Here is my solution:

val svc = url(#your_url)
val response = Http(svc OK dispatch.as.json4s.Json)
response onComplete {
    // do_what_you_want
}
while(!response.isCompleted) {
    Thread.sleep(1000)
}
// return_what_you_want

So here I use "isCompleted" to help me to wait until finish. So it is a trick to convert async to sync.

jjmerelo
  • 22,578
  • 8
  • 40
  • 86
Haimei
  • 12,577
  • 3
  • 50
  • 36