简体   繁体   English

从API获取所有页面

[英]Getting all the pages from an API

This is something I struggle with, or whenever I do it it seems to be messy. 这是我挣扎的事情,或者每当我这样做时,它似乎都很混乱。 I'm going to ask the question in a very generic way as it's not a single problem I'm really trying to solve. 我将以非常通用的方式提出这个问题,因为这不是我真正想要解决的问题。

I have an API that I want to consume some data from, eg via: 我有一个API,我想从中消耗一些数据,例如:

def get_api_results(page)
  results = HTTParty.get("api.api.com?page=#{page}")
end

When I call it I can retrieve a total. 当我打电话给它时,我可以检索一个总数。

results["total"] = 237

The API limits the number of records I can retrieve in one call, say 20. So I need to call it a few more times. API限制了我在一次调用中可以检索的记录数,比如说20个。所以我需要多次调用它。

I want to do something like the following, ideally breaking it into pieces so I can use things like delayed_job..etc 我想做类似以下的事情,理想情况下将其分解成碎片,这样我就可以使用delayed_job..etc之类的东西

def get_all_api_pages
  results = get_api_results(1)
  total = get_api_results(1)["total"]

  until page*20 > total do |p|
    results += get_api_results(p)
  end
end

I always feel like I'm writing rubbish whenever I try and solve this (and I've tried to solve it in a number of ways). 每当我尝试解决这个问题时,我总觉得自己在写垃圾(而且我试图以多种方式解决它)。 The above, for example, leaves me at the mercy of an error with the API, which knocks out all my collected results if I hit an error at any point. 例如,上面的内容让我受到API错误的支配,如果我在任何时候遇到错误,它会敲掉我收集的所有结果。

Wondering if there is just a generally good, clean way of dealing with this situation. 想知道是否只有一种通常良好,干净的方式来处理这种情况。

I don't think you can have that much cleaner...because you only receive the total once you called the API. 我认为你不能那么干净......因为你只有在调用API后才收到总数。 Have you tried to build your own enum for this. 你有没有尝试为此建立自己的枚举。 It encapsulates the ugly part. 它封装了丑陋的部分。 Here is a bit of sample code with a "mocked" API: 以下是一些带有“模拟”API的示例代码:

class AllRecords
  PER_PAGE = 50

  def each
    return enum_for(:each) unless block_given?
    current_page = 0
    total = nil
    while total.nil? || current_page * PER_PAGE < total
      current_page += 1
      page = load_page(current_page)
      total = page[:total]
      page[:items].each do |item|
        yield(item)
      end
    end
  end

  private

  def load_page(page)
    if page == 5
      {items: Array.new(37) { rand(100) }, total: 237}
    else
      {items: Array.new(50) { rand(100) }, total: 237}
    end
  end
end

AllRecords.new.each.each_with_index do |item, index|
  p index
end

You can surely clean that out a bit but i think that this is nice because it does not collect all the items first. 你可以肯定地清理一下,但我认为这很好,因为它不会首先收集所有项目。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM