Spray / Akka missing

MyService.scala:33: could not find implicit value for parameter eh: spray.routing.ExceptionHandler

I encountered a “missing implicit” compilation error using Akka in spray.io code that makes an HTTP call to a separate server server as part of the http get response. The code needs to import quite a few Spray and Akka libraries, so it’s a little difficult to understand if there can be some library conflicts that cause this, and I would prefer how to logically track this problem for this and other cases.

Missing implicit occurs when calling runRoute(myRoute)

Here is the code:

 import spray.routing._ import akka.actor.Actor import akka.actor.ActorSystem import spray.http._ import MediaTypes._ import akka.io.IO import spray.httpx.RequestBuilding._ import scala.concurrent.Future import spray.can.Http import spray.http._ import akka.util.Timeout import HttpMethods._ import akka.pattern.ask import akka.event.Logging import scala.concurrent.duration._ // we don't implement our route structure directly in the service actor because // we want to be able to test it independently, without having to spin up an actor class MyServiceActor extends Actor with MyService with akka.actor.ActorLogging { log.info("Starting") // the HttpService trait defines only one abstract member, which // connects the services environment to the enclosing actor or test def actorRefFactory = context // this actor only runs our route, but you could add // other things here, like request stream processing // or timeout handling def receive = runRoute(myRoute) } // this trait defines our service behavior independently from the service actor trait MyService extends HttpService { implicit val system: ActorSystem = ActorSystem() implicit val timeout: Timeout = Timeout(15.seconds) import system.dispatcher // implicit execution context //val logger = context.actorSelection("/user/logger") val logger = actorRefFactory.actorSelection("../logger") val myRoute = { def forward(): String = { logger ! Log("forwarding to backend") val response: Future[HttpResponse] = (IO(Http) ? Get("http:3080//localhost/backend")).mapTo[HttpResponse] "<html><body><h1>api response after backend processing</h1></body></html>" } path("") { get { respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here complete(forward) } } } } } 

I am wondering what is the best way to solve this problem, I hope that you can understand how to solve such problems with the lack of implications, since they are not just tracked by nature.

EDIT: when I try to directly pass implicits, as in the following @christian example, I get:

MyService.scala:35: ambiguous implicit values: both value context in trait Actor of type => akka.actor.ActorContext and value system in trait MyService of type => akka.actor.ActorSystem match expected type akka.actor.ActorRefFactory
RoutingSettings.default, LoggingContext.fromActorRefFactory) ^

It is not entirely clear why the concrete, as in @christian's answer, leaves room for ambiguity for the compiler ...

+7
scala akka spray
source share
2 answers

runRoute expects several implications. You are missing an import:

 import spray.routing.RejectionHandler.Default 

Update: I think we also had some problems with runRoute, because we explicitly provide implicit parameters:

 runRoute(route)(ExceptionHandler.default, RejectionHandler.Default, context, RoutingSettings.default, LoggingContext.fromActorRefFactory) 

Update2: To fix the last error, delete the creation of the ActorSystem (in MyService you get an actor system from MyServiceActor, so you should use an annotation like self). This compiles:

 import akka.actor.Actor import akka.io.IO import spray.httpx.RequestBuilding._ import spray.http.MediaTypes._ import spray.routing.{RoutingSettings, RejectionHandler, ExceptionHandler, HttpService} import spray.util.LoggingContext import scala.concurrent.Future import spray.can.Http import spray.http._ import akka.util.Timeout import HttpMethods._ import akka.pattern.ask import akka.event.Logging import scala.concurrent.duration._ // we don't implement our route structure directly in the service actor because // we want to be able to test it independently, without having to spin up an actor class MyServiceActor extends Actor with MyService with akka.actor.ActorLogging { log.info("Starting") // the HttpService trait defines only one abstract member, which // connects the services environment to the enclosing actor or test implicit def actorRefFactory = context // this actor only runs our route, but you could add // other things here, like request stream processing // or timeout handling def receive = runRoute(myRoute)(ExceptionHandler.default, RejectionHandler.Default, context, RoutingSettings.default, LoggingContext.fromActorRefFactory) } // this trait defines our service behavior independently from the service actor trait MyService extends HttpService { this: MyServiceActor => implicit val timeout: Timeout = Timeout(15.seconds) implicit val system = context.system //val logger = context.actorSelection("/user/logger") val logger = actorRefFactory.actorSelection("../logger") val myRoute = { def forward(): String = { //logger ! Log("forwarding to backend") val response: Future[HttpResponse] = (IO(Http) ? Get("http:3080//localhost/backend")).mapTo[HttpResponse] "<html><body><h1>api response after backend processing</h1></body></html>" } path("") { get { respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here complete(forward) } } } } } 
+2
source share

I came across the same “could not find the implicit value for the eh: spray.routing.ExceptionHandler” parameter earlier. I tried the @Christian approach, but saw a few "implicit values ​​for xxx" creeping up. After I checked the error message, I discovered the addition of implicit val system = context.system to the actor, which runRoute solved the problem.

+19
source share

All Articles