Search code examples
scalaakka

Return value from JSON in Scala (akka and spray)


I don't know what to say. Second day straight I try to get the value from JSON object juggling many Scala libraries. This one is Akka with spray. I try to save where on earth id to variable and return it from function/method. I does not matter for me if it will be Future or not, but I'm stuck at this statement int = for {lel <- ss} yield lel. Whatever I try, I always get the initial value of int wherever it is a class, case class, Future[Int] or Int. Please advice.

    scala> def queryLocation(location: String): Future[Int] = {
     | var int: Any = Future{0} ; val locUri = Uri("https://www.metaweather.com/api/location/search/").withQuery(Uri.Query("query" -> location))
     | 
     | val req = HttpRequest(uri = locUri, method = HttpMethods.GET);val respFuture = Http().singleRequest(req);
     | respFuture.onComplete{
     | case Success(value) => {
     | val r = Unmarshal(value).to[Seq[Search]]
     | val ss = for { reich <- r  } yield reich(0).woeid
     | int =  for {lel <- ss} yield lel
     | }
     | }
     | int.asInstanceOf[Future[Int]] }
       respFuture.onComplete{
                            ^
On line 5: warning: match may not be exhaustive.
       It would fail on the following input: Failure(_)
def queryLocation(location: String): scala.concurrent.Future[Int]

scala> Await.result(queryLocation("Warsaw"), 1.second)
val res221: Int = 0

Solution

  • The problem is that you create a Future which is eagerly executed:

    var int: Any = Future{0}
    

    I see different problems here:

    1. Don´t use var. A Future is an asynchronous computation and there is no sense in mutating anything in there.
    2. Why do you declare a variable as Any?. It is a Future.

    And this for-comprehension:

    int =  for {lel <- ss} yield lel
    

    looks bad. And maybe it is because Scala future is not referentially transparent. So avoid that. If you want to deserialize the content of the response just use map:

    val future = HttpRequest(uri = locUri, method = HttpMethods.GET).map(content => Unmarshal(value))
    
    Await.result(future, 1.second)