David Caseria
David Caseria

Reputation: 261

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.

Upvotes: 7

Views: 4331

Answers (1)

thirstycrow
thirstycrow

Reputation: 2824

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)
      }
    }
  }
}

Upvotes: 12

Related Questions