Skip to content

Instantly share code, notes, and snippets.

@JonNorman
Last active December 10, 2018 17:06
Show Gist options
  • Save JonNorman/fabdbe506da15d130eb3ea1135303a42 to your computer and use it in GitHub Desktop.
Save JonNorman/fabdbe506da15d130eb3ea1135303a42 to your computer and use it in GitHub Desktop.
week-10-exercises

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.

  1. Get a Song from the SongAPI by name or artist and print it out.

  2. Put a Song into the SongAPI, then get it in a subsequent call to the SongAPI.

  3. Try adding a method to SongAPI def removeSong(name: String, artist: String): Future[Boolean]to remove a song from the catalogue. The Future[Boolean] should be true if the song was in there and deleted and false if the song wasn't there.

  4. 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 {
      ()
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment