Newbie question on API: returning result to controller from a Future in a service

90 views
Skip to first unread message

Dennis O

unread,
Nov 20, 2015, 7:05:29 PM11/20/15
to scala-user
Hi,

Making first steps and trying to build a simple API mostly to learn & explore.
Sorry for long copy-pastes.
Using akka-http 2, Scala 2.11.7, Slick 3.01

Given:

1. I have a model "model.prices" with a getTotals() method that is supposed to return just one number (Int) back to the router (i.e. main page here with routes definition):

package com.myproject.model

import slick.driver.MySQLDriver.api._
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.concurrent.Future

object prices {


def getTotals(): Unit = {
val db = Database.forConfig("mysql1")
val timeout = 20.seconds

val q = sql"SELECT count(*) as total FROM prices".as[String]

val f: Future[Seq[String]] = db.run(q)

f.onSuccess { case s => println(s"Result: $s") }
f.onFailure { case s => -1 }

// Await.result(
// db.run(q).map { res =>
// // res is a Vector[String]
// println(res)
// }, timeout
// )
}

}

So in the end I have a Future (and as you see - tried Await.result too). Not sure how to send it back. Just printing w/o problems for now.


2. In the main file I have a route, that's supposed to receive result from that model:

package com.myproject

// importing this for a package object

import akka.actor.ActorSystem

import akka.http.scaladsl.model._

import akka.http.scaladsl.Http
import akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import scala.io.StdIn.readLine
import StatusCodes._

import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import spray.json._
import spray.json.DefaultJsonProtocol._


import model.prices


object main extends App with SprayJsonSupport {

implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
implicit val ec = system.dispatcher

val route =
path("hello") {
get {

println(prices.getTotals())

val strout = "trying to get a result from model.prices".toJson
complete(strout)
}
} ~
complete(StatusCodes.NotFound, "Not found")

val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)

println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
readLine() // for the future transformations
bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
.onComplete(_ ⇒ system.terminate()) // and shutdown when done

}


Cannot wrap my head around the following:
1. How to receive an Int, not Future, result from a model that operates with a Future inside it?
2. Would not it be architecturally more correct for my service/model to actually return a Future, and for the controller to "unwrap" it?
3. ... maybe this should be question #1 in fact: do we need Future here at all?? If not, what would be my steps then?


Thank you!
D.

Tim Harper

unread,
Nov 22, 2015, 1:21:16 PM11/22/15
to scala-user
You're looking for the onSuccess directive. It's close sibling, onComplete, which, given a Future[T] yields a scala.util.Try[T], which is either a scala.util.Success(result: T) or scala.util.Failure(exception: Throwable)

Reply all
Reply to author
Forward
0 new messages