Search code examples
scalaakkasprayakka-httpspray-client

Why does mapTo fail in Akka HTTP client?


I have a Akka HTTP service which returns a string, as shown below:

val route1: Route = {
    path("hello") {
      get{
        complete{
          println("Inside r1")
          "You just accessed hello"
        }
      }
   }
}

I have a Akka HTTP client which tries to access this route. But the below code fails:

  val future1 = Http()
    .singleRequest(
      HttpRequest(method = HttpMethods.GET,
        uri = "http://localhost:8187/hello")).mapTo[String]

  future1.onSuccess({
    case y:String=>println(y)
  })

I get no output at all. But, if I use unmarshal instead with a flatMap, I get the output:

 val future1:Future[String] = Http()
    .singleRequest(
      HttpRequest(method = HttpMethods.GET,
                  uri = "http://localhost:8187/hello")).flatMap(resp => Unmarshal(resp).to[String])

Why is mapTo failing here and why do I need flatMap and Unmarshal?

Edit:

I understood the need for Unmarhsal and I am trying to understand the difference between map and flatMap

For example, the below code gives me the result as expected:

val future1:Future[String] = Http().singleRequest(
          HttpRequest(method = HttpMethods.GET,
                      uri = http://localhost:8187/hello")).flatMap(testFlatFunc)

  def testFlatFunc(x:HttpResponse):Future[String]={
    return Unmarshal(x).to[String]
  }

But, if I try to replace it with a map, as below I get the output as FulfilledFuture(You just accessed hello)

 val future1:Future[String] = Http()
    .singleRequest(
      HttpRequest(method = HttpMethods.GET,
                  uri = "http://localhost:8187/hello")).map(testFunc)

  def testFunc(x:HttpResponse): String={
    return Unmarshal(x).to[String].toString
  }

Solution

  • See the docs for mapTo below

      /** Creates a new `Future[S]` which is completed with this `Future`'s result if
       *  that conforms to `S`'s erased type or a `ClassCastException` otherwise.
       */
    

    mapTo[S] essentially corresponds to a cast. The Http().singleRequest produces a Future[HttpResponse], and HttpResponse cannot be bluntly cast to String.

    Umarshalling is necessary to specify a meaningful logic to convert to String. So in your case you have an implicit Unmarshaller in scope that provides this. And this is most likely the default stringUnmarshaller from Akka-HTTP predefined set. More info on this can be found in the docs.