No commit activity in last 3 years
No release in over 3 years
This gem adds the ability to read shopify API call limits to the ShopifyAPI gem
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 2.6.0
>= 1.2.2

Runtime

>= 1.2.2
 Project Readme

shopify-api-limits¶ ↑

My friend Dave (aka “hunkybill”) posted a problem to me one day about ShopifyAPI call limits, offering a case of beer if I could find a solution: forums.shopify.com/categories/9/posts/49003

So in the HTTP headers, the ShopifyAPI will return to you in each API request how many calls you’ve made, as well as the maximum number of calls available.

Problem¶ ↑

ActiveResource does not make it easy to read the HTTP response headers, since the method #request in ActiveResource::Connection does not save a reference to the HTTP response:

# Makes a request to the remote service.
def request(method, path, *arguments)
  result = ActiveSupport::Notifications.instrument("request.active_resource") do |payload|
    payload[:method]      = method
    payload[:request_uri] = "#{site.scheme}://#{site.host}:#{site.port}#{path}"
    payload[:result]      = http.send(method, path, *arguments)
  end
  handle_response(result) # <-- right here:  handle_response returns an instance of HTTPResponse but doesn't save a ref to it!
rescue Timeout::Error => e
  raise TimeoutError.new(e.message)
rescue OpenSSL::SSL::SSLError => e
  raise SSLError.new(e.message)
end

Solution¶ ↑

Hack ActiveResource::Connection to introduce a new attr_reader :response and capture the returned instance of HTTPResponse provided by net/http from the #handle_response method.

module ActiveResource
  class Connection
    # HACK:  Add an attr_reader for response
    attr_reader :response

    # capture the original #handle_response as an unbound method instead of using alias
    handle_response = self.instance_method(:handle_response)

    # re-implement #handle_response to capture the returned HTTPResponse to an instance var.
    define_method(:handle_response) do |response| 
      @response = handle_response.bind(self).call(response)
    end 
  end
end

Now it’s possible to access the HTTPResponse instance directly from ActiveResource, via:

foo = ActiveResource::Base.connection.response['http-header-param-foo']

Installation¶ ↑

gem "shopify_api"
gem "shopify-api-limits"

Usage¶ ↑

count_shop = ShopifyAPI.credit_used :shop
limit_shop = ShopifyAPI.credit_limit :shop

count_global = ShopifyAPI.credit_used :global
limit_global = ShopifyAPI.credit_limit :global

Generally, you shouldn’t need to use the methods above directly – rather, they’re used under-the-hood by the following helpful methods which don’t require a scope (:shop/:global): If the :global scope has fewer calls available than the :local scope, the methods will operate upon the :global scope; otherwise, values will be returned based upon the :shop scope.

unless ShopifyAPI.credit_maxed?
  #make a ShopifyAPI call
end

until ShopifyAPI.credit_maxed? || stop_condition
  # make some ShopifyAPI calls
end

while ShopifyAPI.credit_left || stop_condition
  # make some ShopifyAPI calls
end

A special bonus for retrieving large recordsets > 250 records¶ ↑

Shopify places a hard limit of 250 on the number of records returned in a single request. There are ways around this, including one listed here bit.ly/kgwCRc which involves manually calculating the total & number of pages then iterating to make several API calls. This gem encapsulates this behaviour allowing you to make what feels like a single call to the ShopifyAPI. Simply set :params => {:limit => false}. False as in, “no limit”

For example, imagine a store which has 251 orders and you want to fetch them all. Since the maximum number of records returned in a single request is 250, 2 requests must be made to the API in order to fetch all 251 records.

records = ShopifyAPI::Order.all(:params => {:limit => false})
puts records.count
=> 251

Without {:limit => false}, the normal behaviour will operate (ie: just one request with 250 records returned):

records = ShopifyAPI::Order.all(:params => {:limit => 250})
puts records.count
=> 250

If you don’t have enough API credits to perform the multiple requests to serve your desired recordset, a ShopifyAPI::Limits::Error will be raised:

puts ShopifyAPI::Order.count
=> 251

puts ShopifyAPI.credit_left
=> 1

begin
  rs = ShopifyAPI::Order.all(:params => {:limit => false})
rescue ShopifyAPI::Limits::Error
  puts "Uhoh...didn't have enough credits to do that.  Maybe you wanna' queue your task for a later date."
end