Write an App that attempts to do the following tasks, and run it a few times. Each task should handle the case where
the Future
fails, as well as if it doesn't give back what you would expect.
-
Get a
Song
from theSongAPI
by name or artist and print it out. -
Put a
Song
into theSongAPI
, then get it in a subsequent call to theSongAPI
. -
Try adding a method to SongAPI
def removeSong(name: String, artist: String): Future[Boolean]
to remove a song from the catalogue. TheFuture[Boolean]
should betrue
if the song was in there and deleted andfalse
if the song wasn't there. -
Can you make your app retry if a request fails? Can you make it retry
n
times if a request fails?
Copy the code below into a scala file and fill in the implementation of SongClient
.
import scala.concurrent.Future
import scala.util.Random
import scala.concurrent.ExecutionContext.Implicits.global
object SongClient extends App {
//TODO
}
/**
* This is a mock API over a fictional song database. It allows a user to get song information and to enter
* new songs into the API. In reality there would be some serialisation - it would return JSON representations of the
* Songs, but for now we will just share the `SongAPI.Song` model across our client and the API.
*/
object SongAPI {
case class Song(name: String, artist: String, url: String)
/*
The catalogue is modelled as a mutable Set. In reality we could model this more functionally but that's beyond
the scope of this example so let's allow ourselves some mutability.
*/
private val catalogue = scala.collection.mutable.HashSet(
Song("Hymn To Freedom", "Oscar Peterson", "https://open.spotify.com/track/2T1ACKqq6GEozD390n16Ve?si=khI-dvYPRzuqMP6ZvgJTRQ"),
Song("Easily", "Bruno Major", "https://open.spotify.com/track/2k9N4caeCIJLOWwWwssrEM?si=GZJ3_0FuQke-hDar5H5DAg"),
Song("Sorceress", "Jordan Rakei", "https://open.spotify.com/track/03yib980AUBlXsJ8JJz54l?si=cDskjT7VQIuw86zGTQPeBQ"),
Song("Holding Back The Years", "Gretchen Parlato", "https://open.spotify.com/track/7p72uUp9qIlFP1IRbAvcox?si=Rl_P6t2YQ0ivLrj_H5johQ"),
Song("All That I Can Say", "Gretchen Parlato", "https://open.spotify.com/track/0rEVw979CI6wMZb3snSE7K?si=rRsq5BoMQ4udEUfkOqdC9w")
)
// add a song to the catalogue
def putSong(song: Song): Future[Boolean] =
Future {
Thread.sleep(200)
maybeFail()
catalogue.add(song)
}
// get a song by name from the catalogue
def getSongByName(name: String): Future[Option[Song]] =
Future {
Thread.sleep(300)
maybeFail()
catalogue.find(_.name == name)
}
// get a song by artist from the catalogue
def getSongsByArtist(artist: String): Future[List[Song]] = {
Future {
Thread.sleep(300)
maybeFail()
catalogue.filter(_.artist == artist).toList
}
}
// a helper method to simulate a failed request
private def maybeFail(): Unit =
// fail 20% of the time
if (Random.nextInt() % 5 == 0) {
new RuntimeException("Catalogue offline. Song not pushed to catalogue")
} else {
()
}
}