Scala spray-client define implicits for AKKA ActorRefFactory

actor, akka, implicits, scala, spray

Solution

Here's one solution:

import akka.actor.ActorSystem
import spray.http.{HttpRequest, HttpResponse}
import scala.concurrent.Future
import spray.client.pipelining._

trait WebClient {
  def get(url: String): Future[String]
}

class SprayWebClient(implicit system: ActorSystem) extends WebClient {
  import system.dispatcher

  val pipeline: HttpRequest => Future[HttpResponse] = sendReceive

  def get(url: String): Future[String] = {
    val r = pipeline (Get("http://some.url/"))
    r.map(_.entity.asString)
  }
}

and here's another that keeps the original `WebClient.get` signature:

import akka.actor.ActorSystem
import spray.http.{HttpRequest, HttpResponse}
import scala.concurrent.Future
import spray.client.pipelining._

trait WebClient {
  def get(url: String)(implicit system: ActorSystem): Future[String]
}

object SprayWebClient extends WebClient {
  def get(url: String)(implicit system: ActorSystem): Future[String] = {
    import system.dispatcher

    val pipeline: HttpRequest => Future[HttpResponse] = sendReceive
    val r = pipeline (Get("http://some.url/"))
    r.map(_.entity.asString)
  }
}

The second one is a bit more expensive because the pipeline is created anew every time even if it is theoretically static per `ActorSystem`. I would prefer the first solution and try to find a way to propagate the `WebClient` through your application (by using the cake pattern, by passing it around explicitly, or by using other dependency injection techniques).

Problem

I'm trying to write a simple HTTP client using Scala and spray-client. I'm basing my client on the examples given on Spray docs. My issue is that the example is creating a new implicit ActorSystem i.e. ``` implicit val system = ActorSystem() ``` but I want my client to be reusable and not create a new ActorSystem. Here's the gist of my code. ``` trait WebClient { def get(url: String)(implicit system: ActorSystem): Future[String] } object SprayWebClient extends WebClient { val pipeline: HttpRequest => Future[HttpResponse] = sendReceive def get(url: String): Future[String] = { val r = pipeline (Get("http://some.url/")) r.map(_.entity.asString) } } ``` But I am getting two compiler errors regarding implicits ``` implicit ActorRefFactory required: if outside of an Actor you need an implicit ActorSystem, inside of an actor this should be the implicit ActorContext WebClient.scala ... ``` and ``` not enough arguments for method sendReceive: (implicit refFactory: akka.actor.ActorRefFactory, implicit executionContext: scala.concurrent.ExecutionContext, implicit futureTimeout: akka.util.Timeout)spray.http.HttpRequest => scala.concurrent.Future[spray.http.HttpResponse]. Unspecified value parameters refFactory, executionContext. WebClient.scala... ``` How should I change the API definitions?

Original source