我正在尝试实现一个将请求缓存到外部API的系统。如果响应在缓存中,则不应向外部站点发出请求。
我有两种方法:
// Check to see if the response is in the database
def checkCache(searchParameters: JsValue): Future[Option[JsValue]]
// Call the external API and get the JSON response
def getResponse(path: String): Future[JsValue]
然后我尝试执行以下操作:
val json: Future[JsValue] = for {
databaseJson <- checkCache(searchParameters)
externalJson <- getResponse(path)
} yield databaseJson match {
case None => externalJson
case Some(x) => x
}
这样做有效,但是一直向外部API发出请求,即使返回了缓存结果也是如此。这显然不是我想要的,因为它很慢。
我该如何解决这个问题?
答案 0 :(得分:4)
for comprehension映射了期货,而不是其中的Option。您的代码将转换为此
checkCache(searchParameters) flatMap { databaseJson =>
getResponse(path) map { externalJson =>
databaseJson match {
case None => externalJson
case Some(x) => x
}
}
}
所以你总是明显地打电话给getResponse()
。
你需要的东西(未经测试):
checkCache(searchParameters) flatMap { databaseJson =>
databaseJson match {
case None => getResponse(path)
case Some(x) => Future.successful(x)
}
}
答案 1 :(得分:2)
这有点俗气,但仍然:
checkCache(params) map (_.get) fallbackTo getResponse(path)
也未经过测试。
更新
我不喜欢None.get
转换为失败,但实际上这根本不是俗气,而是很自然。更自然地:
checkCache(params) filter (_.nonEmpty) map (_.get) fallbackTo getResponse(path)
Some.get
现在只是一个疣,因为两个期货的不对称性(它们不是Option
)。
答案 2 :(得分:2)
你也可以试一试:
val json: Future[JsValue] = for {
databaseJson <- checkCache(searchParameters)
json <- databaseJson.fold(getResponse(path))(js =>Future.successful(js))
} yield json
与Marius Soutier的回答类似,但在理解中通过fold
权限进行选项检查。