Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to make an Akka HTTP core client request inside an Actor?

Below is a simple actor which is required to make a HTTP call to receive data from an API. According to the Akka HTTP Core Request-Level Client-Side API only the ActorSystem and ActorMaterializer are needed implicitly.

class MyActor extends Actor {

  import context.system
  implicit val materializer = ActorMaterializer()

  override def receive: Receive = {
    case _ => {
      val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = "http://akka.io"))
      responseFuture onComplete {
        case Success(res) => println(res)
        case Failure(t) => println("An error has occured: " + t.getMessage)
      }
    }
  }
}

However, when attempting to compile the application I receive the following error messages:

Error:(18, 48) ambiguous implicit values: both value context in trait Actor of type => akka.actor.ActorContext and method system in trait ActorContext of type => akka.actor.ActorSystem match expected type akka.actor.ActorRefFactory
  implicit val materializer = ActorMaterializer()

Error:(18, 48) implicit ActorRefFactory required: if outside of an Actor you need an implicit ActorSystem, inside of an actor this should be the implicit ActorContext
  implicit val materializer = ActorMaterializer()

Error:(18, 48) not enough arguments for method apply: (implicit context: akka.actor.ActorRefFactory)akka.stream.ActorMaterializer in object ActorMaterializer. Unspecified value parameter context.
  implicit val materializer = ActorMaterializer()

Error:(22, 70) could not find implicit value for parameter fm: akka.stream.Materializer 
  val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = "http://akka.io"))

Error:(22, 70) not enough arguments for method singleRequest: (implicit fm: akka.stream.Materializer)scala.concurrent.Future[akka.http.scaladsl.model.HttpResponse]. Unspecified value parameter fm.
  val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = "http://akka.io"))

Error:(23, 22) Cannot find an implicit ExecutionContext. You might pass an (implicit ec: ExecutionContext) parameter to your method or import scala.concurrent.ExecutionContext.Implicits.global.
  responseFuture onComplete {

Error:(23, 22) not enough arguments for method onComplete: (implicit executor: scala.concurrent.ExecutionContext)Unit. Unspecified value parameter executor.
  responseFuture onComplete {

Is this the correct way to make a HTTP call inside an Akka Actor?

Edit

Included import ExecutionContext.Implicits.global to fix the last two ExecutionContext errors.

like image 770
David Caseria Avatar asked Aug 27 '15 03:08

David Caseria


1 Answers

An implicit ActorRefFactory is required to create the ActorMaterializer. The context property defined in the Actor trait extends ActorRefFactory, and it's implicit. The system property on context, which you imported explicitly, is another implicit candidate for ActorRefFactory, because ActorSystem extends ActorRefFactory.

My suggestion is removing the import and passing it explicitly where it is needed.

class MyActor extends Actor {

  // Do not import context.system
  // import context.system
  implicit val materializer = ActorMaterializer()

  override def receive: Receive = {
    case _ => {
      // use context.system explicitly
      val responseFuture: Future[HttpResponse] = Http(context.system)
        .singleRequest(HttpRequest(uri = "http://akka.io"))
      responseFuture onComplete {
        case Success(res) => println(res)
        case Failure(t) => println("An error has occured: " + t.getMessage)
      }
    }
  }
}
like image 199
thirstycrow Avatar answered Sep 26 '22 15:09

thirstycrow