Coder Social home page Coder Social logo

shopify-api-limits's Introduction

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

shopify-api-limits's People

Contributors

christocracy avatar

Stargazers

 avatar

Watchers

 avatar

Forkers

wishery

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.