0
object IO {

  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String = {
    Http(link)
      .param("access_token", apiKey)
      .asString
      .body
  }
}

class SongService {
  private def retrieveSongId(songName: String): Option[JsValue] = {
    val formattedSongName = songName.replace(" ", "%20")
    val searchLink = "https://api.genius.com/search?q=" + formattedSongName

    //impure call
    val geniusStringResponse = IO.getHtmlFromWebsiteViaHttp(searchLink, apiKey)

   //Extra processing on geniusStringResponse
  }
}

我目前的设计是我将有一个服务类,负责通过外部 API 获取一些信息。现在我明白了,不可能有 100% 纯函数。

我的问题:处理需要在 Scala/FP 中连接到外部 API 的情况的最佳方法是什么?目的是通过最小化不纯函数来拥有最合适的“函数式编程风格”

目前,我将所有 API 调用封装在 IO 对象中。这够合适吗?我看到了单子的例子。在这种情况下我应该合并一个单子风格吗?

4

1 回答 1

0

This isn't so much an FP problem, as I don't see any problems with your code in terms of FP, but what you should do, in my opinion is use dependency injection, such that, for testing, you can substitute a test class for IO that has a guaranteed response. Something like this:

abstract class IO {
  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String
}

class IOImpl extends IO {
  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String = {
    Http(link)
      .param("access_token", apiKey)
      .asString
      .body
  }
}

class IOTestImpl extends IO {
  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String = ??? //some test HTML
}

And then in your service:

class SongService(io: IO) {
  private def retrieveSongId(songName: String): Option[JsValue] = {
    val formattedSongName = songName.replace(" ", "%20")
    val searchLink = "https://api.genius.com/search?q=" + formattedSongName
    val geniusStringResponse = io.getHtmlFromWebsiteViaHttp(searchLink, apiKey)
   //Extra processing on geniusStringResponse
  }
}

Then when you instantiate your SongService, pass it IOTestImpl in testing and IOImpl otherwise. You might find some relevant information on dependency injection and database access objects.

于 2018-08-30T21:20:11.680 回答