Scala 中的递归 HTTP 请求

Recursive HTTP-requests in Scala

我需要递归请求,然后将所有模型收集到一个列表中,但不明白该怎么做。请告诉我我的想法是否正确?

package kindSir.main

import dispatch.Defaults._
import dispatch._
import kindSir.models._
import org.json4s._
import org.json4s.jackson.JsonMethods._

object ApplicationMain extends App {

  def fetchMergeRequests(startPage: Int = 1): Future[List[MergeRequest]] = {
    val requestsUrl = url(s"https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab-ce/merge_requests?state=opened&per_page=3&page=${startPage}")
    Http(requestsUrl).map { res =>
      (parse(res.getResponseBody), res.getHeader("X-Next-Page").toInt) match {
        case (list@JArray(_), nextPage: Int) =>
          val currentList: List[MergeRequest] = MergeRequest.parseList(list).get
          val nextPageListFuture: Future[List[MergeRequest]] = fetchMergeRequests(nextPage)
          // And how to merge these two lists?
        case (list@JArray(_), _) => MergeRequest.parseList(list).get
        case _ => throw new RuntimeException(s"No merge requests for project found")
      }
    }
  }

}

您在这里要处理的主要问题是您试图将已有的数据 (List[MergeRequest]) 与您将来检索的数据 (Future[List[MergeRequest]]) 结合起来。要处理这种情况,您需要做几件事:

  • 对 HTTP 请求的结果使用 flatMap 而不是 map。这允许您在递归内部发出更多 HTTP 请求,但将它们映射回单个 Future.
  • 对递归的结果调用 map fetchMergeRequests(nextPage) 以将您已有的数据与递归的未来数据相结合。
  • 将另一个列表包装在 Future.successful() 中,因为 flatMap 要求所有模式匹配 return a Future — 除了例外。

我不熟悉你使用的库,所以我没有测试过,但我认为你的代码应该像这样工作:

def fetchMergeRequests(startPage: Int = 1): Future[List[MergeRequest]] = {
  val requestsUrl = url(s"https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab-ce/merge_requests?state=opened&per_page=3&page=${startPage}")
  Http(requestsUrl).flatMap { res =>
    (parse(res.getResponseBody), res.getHeader("X-Next-Page").toInt) match {
      case (list@JArray(_), nextPage: Int) =>
        val currentList: List[MergeRequest] = MergeRequest.parseList(list).get
        val nextPageListFuture: Future[List[MergeRequest]] = fetchMergeRequests(nextPage)
        nextPageListFuture.map(nextPageList => currentList ++ nextPageList)
      case (list@JArray(_), _) =>
        Future.successful(MergeRequest.parseList(list).get)
      case _ => throw new RuntimeException(s"No merge requests for project found")
    }
  }
}