Question

I need to query a RESTful service that always returns a JSON response. I need to contact it a few times, always with some more information that I learned from the previous request. I'm using Akka2, Scala, Jerkson and Spray-Can.

My current approach seems to work, but it looks ugly and requires nesting everything. I read that there should be some techniques available regarding chaining and such, but I couldn't figure out how to apply them to my current use-case.

Here is the code I'm talking about:

def discoverInitialConfig(hostname: String, bucket: String) = {

    val poolResponse: Future[HttpResponse] = 
      HttpDialog(httpClient, hostname, 8091)
      .send(HttpRequest(uri = "/pools"))
      .end

    poolResponse onComplete { 
      case Right(response) =>
        log.debug("Received the following global pools config: {}", response)

        val pool = parse[PoolsConfig](response.bodyAsString)
          .pools
          .find(_("name") == defaultPoolname)
          .get

        val selectedPoolResponse: Future[HttpResponse] =
          HttpDialog(httpClient, hostname, 8091)
          .send(HttpRequest(uri = pool("uri")))
          .end

        selectedPoolResponse onComplete {
          case Right(response) =>
            log.debug("Received the following pool config: {}", response)

            println(response.bodyAsString)

          case Left(failure) =>
            log.error("Could not load the pool config! {}", failure)
        }

      case Left(failure) =>
        log.error("Could not load the global pools config! {}", failure)
    }

I think you can see the pattern. Contact the REST service, read it, on success parse it into a JSON case class, extract information out and then do the next call.

My structure here is only two-levels deep but I need to add a third level as well.

Is there a technique available to improve this for better readability or can I only stick with this? If you need any further information I'm happy to provide it. You can see the full code here: https://github.com/daschl/cachakka/blob/f969d1f56a4c90a929de9c7ed4e4a0cccea5ba70/src/main/scala/com/cachakka/cluster/actors/InitialConfigLoader.scala

Thanks, Michael

Was it helpful?

Solution

HttpDialog seems to cover your use case exactly.

OTHER TIPS

I think I found a reasonable shortcut by using the provided reply method from spray-can.

def discoverInitialConfig(hostname: String, bucket: String) = {

val poolResponse: Future[HttpResponse] = 
  HttpDialog(httpClient, hostname, 8091)
  .send(HttpRequest(uri = "/pools"))
  .reply(response => {
    log.debug("Received the following global pools config: {}", response)
    val selectedPool = parse[PoolsConfig](response.bodyAsString)
      .pools.find(_("name") == defaultPoolname).get
    HttpRequest(uri = selectedPool("uri"))
  })
  .reply(response => {
    log.debug("Received the following pool config: {}", response)
    println(response.bodyAsString)
    HttpRequest(uri = "/")
  })
  .end

}

If this is the best available approach, I'll mark it as "answered" but I'm eager to get actual replies from people who know this stuff much better than me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top