Search code examples
scalaakkaunmarshallingakka-http

How to debug akka http's route dsl


I am attempting to create a unmarshaller for akka http, going from avro to a custom case class. But it gives me a very vague error: "could not find implicit value". How can I debug this or make scala give me hint where the problem is?

I set up the route as such:

class MetricsRoute(implicit val system: ActorSystem, implicit val materializer: ActorMaterializer) {
import system.dispatcher

  def getRoute() = {
    path("metrics") {
      put {
        decodeRequest {
          entity(as[Metrics]) { metrics: Metrics =>
            println(metrics.time)
            complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>hi!</h1>"))
          }
        }
      }
    }
  }

In the same class I also created the unmarshaller like this:

  implicit def avroUnmarshaller(): FromRequestUnmarshaller[Metrics] =
    Unmarshaller.withMaterializer {
      implicit ex: ExecutionContext =>
      implicit mat: Materializer =>
        request: HttpRequest => {
          val inputStream = request.entity.dataBytes.runWith(
            StreamConverters.asInputStream(FiniteDuration(3, TimeUnit.SECONDS))
          )

          val reader = new SpecificDatumReader[AvroMetrics](classOf[AvroMetrics])
          val decoder:BinaryDecoder = DecoderFactory.get().binaryDecoder(inputStream, null)

          //AvroMetrics is a case class generated from the avro schema
          val avroMetrics:AvroMetrics = AvroMetrics(0, 0, List())
          reader.read(avroMetrics, decoder)

          Future {
            //converts the avro case class to the case class specific for my application
            convertMetrics(avroMetrics)
          }
        }
  }

But this gives me the very vague 'could not find implicit value' error:

[error] /mypath/MetricsRoute.scala:34: could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[my.package.types.Metrics]
[error]           entity(as[Metrics]) { metrics: Metrics =>
[error]                    ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed

How do I go about debugging what is missing or what I did wrong?

Edit:

Worth noting is when I specify the unmarshaller myself it does work, so changing

entity(as[Metrics]) { metrics: Metrics =>

to

entity(avroUnmarshaller) { metrics: Metrics =>

Which seems to indicate the marshaller code itself isn't wrong, but I've done something wrong with the types?


Solution

  • The compiler is looking for a FromRequestUnmarshaller[Metrics], what you defined is of type () => FromRequestUnmarshaller[Metrics].

    Try defining your implicit with no empty braces, e.g.

    implicit def avroUnmarshaller: FromRequestUnmarshaller[Metrics] = ???
    

    instead of

    implicit def avroUnmarshaller(): FromRequestUnmarshaller[Metrics] = ???
    

    (also, it could be made a val, but that's not relevant to this issue)