0
votes

I'm using Akka's HTTP client library to request a json, and I want to use Play Framework's play-json to parse the json. After I get Akka's HttpResponse, I don't know how to parse the json from the response body, and I don't know how to pass the json to another function in the onComplete directive. Instead, I get this error

overloaded method value parse with alternatives:
[error]   (input: Array[Byte])play.api.libs.json.JsValue <and>
[error]   (input: java.io.InputStream)play.api.libs.json.JsValue <and>
[error]   (input: String)play.api.libs.json.JsValue
[error]  cannot be applied to (scala.concurrent.Future[String])
[error]           val usefulInfo = Json.parse(data)
[error]                                 ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed

What I'm trying right now:

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.stream.ActorMaterializer
import akka.http.scaladsl.model.HttpRequest
import akka.http.scaladsl.unmarshalling.Unmarshal
import play.api.libs.json._

object Main extends App {
    // Boilerplate code from Akka's documentation
    implicit val system = ActorSystem()
    implicit val materializer = ActorMaterializer()
    // needed for the future flatMap/onComplete in the end
    implicit val executionContext = system.dispatcher

    val request = HttpRequest(
        method = HttpMethods.GET,
        uri = "http://example.com/somedata.json"
    )
    var response: Future[HttpResponse] = Http().singleRequest(request)
    response.onComplete{
        case Success(res) => {
            val data = Unmarshal(res).to[String]
            val usefulInfo = Json.parse(data)
            println(usefulInfo)
        }
        case Failure(e)   => println(e)
    }
}

Questions I have are:

  1. How can I parse the json after the Future resolves, with Play Framework's Json.parse()?
  2. How can I store or use this json elsewhere after the response Future resolves? Do I need to do something in the Success case?
1

1 Answers

1
votes

The main problem is that Unmarshal returns a Future so you need to process the data inside the Future to get the String value.

If you want to keep the result rather than just print it, use tranformWith on the initial result rather than onComplete:

val result = Http().singleRequest(request)
  .transformWith {
    case Success(res) =>
      val data = Unmarshal(res).to[String]

      data.map { d =>
        val usefulInfo = Json.parse(d)

        println(usefulInfo)

        usefulInfo
      }
    case Failure(e) =>
      println(e)

      Future.failed(e)
  }

Note that this becomes much cleaner if you leave the printing until the end:

val result = Http().singleRequest(request)
  .flatMap { res =>
    Unmarshal(res).to[String].map { data =>
      Json.parse(data)
    }
  }

result.onComplete {
  case Success(js) =>
    println(s"Success: $js")
  case Failure(e) =>
    println(s"Failure: $e")
}