Рекурсивные HTTP-запросы в Scala - PullRequest
0 голосов
/ 22 октября 2018

Мне нужно сделать рекурсивные запросы, а затем собрать все модели в один список, но я не понимаю, как это сделать.Скажите, пожалуйста, правильно ли я думаю?

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")
      }
    }
  }

}

1 Ответ

0 голосов
/ 23 октября 2018

Основная проблема, с которой вы здесь сталкиваетесь, заключается в том, что вы пытаетесь объединить данные, которые у вас уже есть (List[MergeRequest]), с данными, которые вы получите в будущем (Future[List[MergeRequest]]).Есть несколько вещей, которые вам нужно сделать, чтобы справиться с этим сценарием:

  • Используйте flatMap вместо map в результате запроса HTTP.Это позволяет вам делать дополнительные HTTP-запросы внутри рекурсии, но отображать их обратно на один Future.
  • Вызов map по результату рекурсии fetchMergeRequests(nextPage) для объединения данных, которые у вас уже есть, сбудущие данные из рекурсии.
  • Оберните другой список в Future.successful(), поскольку flatMap требует, чтобы все совпадения с образцом возвращали 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")
    }
  }
}
...