mattmar10
mattmar10

Reputation: 515

How to Design and Call Scala API with Futures

Getting started learning scala and designing/implementing for asynchronous execution. My questions is around how to design APIs (and then call) them for operations that return Unit but may not right away. For example in the snippet below, the function (using Slick 3.0) inserts a user into the DB. Is Unit the correct return type for this function, and if so, how do callers know if/when the newly inserted user is successful?

override def insertOrUpdate(entity: User): Unit = {
     database.run(users.insertOrUpdate(entity))
}

For example, if the above executes asynchronously and a caller looks something like

//create and insert new user with id = 7
val newUser = User(7, "someName")
userRepo.insertOrUpdate(newUser)

How does a caller know whether or not it is safe to do

userRepo.findById(7)

In unit testing, I know that if I follow up the insert call immediately by a findById call, the findById will return nothing, but if I introduce some latency between the insert and find call, it finds the new user. To summarize, what is the proper way to design an API for a function that executes asynchronously but has no natural return value to wrap in a Future?

Upvotes: 0

Views: 452

Answers (1)

Shadowlands
Shadowlands

Reputation: 15074

Generally when working with Futures, you'll want to do any further processing via methods called on the returned Future. Eg.:

val newUser = User(7, "someName")
val future = userRepo.insertOrUpdate(newUser)
future.onSuccess { outcome => // Here, 'outcome' will hold whatever was contained in the Future - Unit in your description above.
   val storedUser = userRepo.findById(7) // This will only execute once the future completes (successfully).
   ...
}

There are plenty of other useful methods for manipulating a Future (or a collection of them), such as "onFailure", "recover", "map" and "flatMap".

Try not to wait on the Future until as late as possible - preferably let Play or Spray or whatever other framework you might happen to be using take care of it for you (see here for Play documentation on doing this, for example).

Finally, in terms of your DB call to insert, I'd look into having the call return at least a boolean, or better still the primary key the new entry was inserted with, rather than Unit.

Upvotes: 3

Related Questions