0.01
No commit activity in last 3 years
No release in over 3 years
A lightweight easy to use Ruby gem for interacting with eBay's Trading API. Using its simple DSL you can quickly and intuitively post XML requests to eBay and rapidly interpret the responses.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.10
~> 10.0
>= 0

Runtime

~> 2.2
 Project Readme

EbayTrader

EbayTrader is a lightweight easy to use Ruby gem for interacting with eBay's Trading API. Leveraging Ruby's missing_method meta-programming DSL techniques, EbayTrader allows you to quickly and intuitively post XML requests to eBay and parses the response. The response data is available in the form of a Hash, actually a HashWithIndifferentAccess so keys :key_name and "key_name" are treated equally, and values are auto-type-cast to String, Fixnum, Float, Boolean, BigDecimal or Money.

Simple example

Let's start with a simple example. Here we will request a list of categories from eBay via a GetCategories API call. Assuming there are no errors or warnings a list of all eBay category names will be printed.

require 'ebay_trader'
require 'ebay_trader/request'

EbayTrader.configure do |config|
  # Configuration is described in the section below...
end

request = EbayTrader::Request.new('GetCategories') do
  CategorySiteID 0
  CategoryParent ARGV.first unless ARGV.empty?
  DetailLevel 'ReturnAll'
  LevelLimit 5
  ViewAllNodes true
end
request.errors_and_warnings.each { |error| puts error.long_message } if request.has_errors_or_warnings?

if request.success?
  category_names = request.response_hash[:category_array][:category].map { |c| c[:category_name] }
  category_names.each { |name| puts name }
end

Notice that in the above example if ARGV is an empty array CategoryParent node will be excluded from the XML document.

CamelCase method names?!

Before you start screaming that this goes against the conventions of the Ruby style guide, let me justify it by reminding you that the eBay XML schema uses CamelCase. It is thus rather counter productive to copy an paste key names from eBay's documentation, manually adapt them to snake_case for the sake of etiquette, then write a method to convert these snake_case key names back into CamelCase.

Nested data example

As shown above the EbayTrader::Request constructor accepts a block with a DSL describing the structure of the XML document to be posted to the eBay Trading API. Additional hierarchy in the XML can be described by nesting more blocks within this DSL. The following example show a call to GetMyeBaySelling to retrieve a list of unsold items.

duration =  30 # days
per_page = 100
page_number = 2

request = EbayTrader::Request.new('GetMyeBaySelling') do
  ErrorLanguage 'en_GB'
  WarningLevel 'High'
  DetailLevel 'ReturnAll'

  UnsoldList do
    Include 'true'
    DurationInDays duration  # 0..60
    Pagination do
      EntriesPerPage per_page
      PageNumber page_number
    end
  end

  ActiveList do 
    Include false
  end
  
  BidList do 
    Include false
  end
           
  DeletedFromSoldList do 
    Include false
  end
                       
  DeletedFromUnsoldList do 
    Include false
  end
                         
  ScheduledList do 
    Include false
  end
                 
  SoldList do 
    Include false
  end
end

For a list of more comprehensive examples please feel free to check out my ebay_trader_support gem. This gem hosts some of the classes and command line tools from my production environment.

Response data

The data tree returned by eBay is accessible through request.response_hash. Response hash is a HashWithIndifferentAccess which has been monkey patched to include a deep_find method. This deep_find method expects an array of key names and performs a depth-first search on response_hash, returning the first value matching the path.

If for example I made a GetItem API call I could determine the current price as follows:

request.response_hash.deep_find([:item, :selling_status, :current_price])

If any of the nodes in the path are absent a value of nil will be returned. deep_find can be instructed return a default should there be no value at the specified path. In the following example $0.00 USD will be returned instead of nil if there is no value at response_hash[:item][:selling_status][:current_price] or the path does not exist.

request.response_hash.deep_find([:item, :selling_status, :current_price], Money.new(0_00, 'USD'))

Configuration

Before using this gem you must configure it with your eBay Developer credentials. Shown below is an example configuration.

EbayTrader.configure do |config|

  config.ebay_api_version = 935

  # Environment can be :sandbox or :production
  config.environment = :sandbox

  # Optional as ebay_site_id can also be specified for each request.
  # 0 for ebay.com [Default]
  # 3 for ebay.co.uk
  config.ebay_site_id = 0

  # If you are getting error messages regarding SSL Certificates
  # you can [temporarily] disable SSL verification.
  # Caution! setting this to false will make you vulnerable to man-in-the-middle attacks.
  # The default value is true
  config.ssl_verify = false  # because I like to live dangerously

  # Optional as auth_token can also be specified for each request.
  config.auth_token = ENV['EBAY_API_AUTH_TOKEN']

  config.dev_id  = ENV['EBAY_API_DEV_ID']
  config.app_id  = ENV['EBAY_API_APP_ID']
  config.cert_id = ENV['EBAY_API_CERT_ID']

  config.ru_name = ENV['EBAY_API_RU_NAME']
  
  # By default price values are represented as BigDecimal
  # This can be changed to any of the following
  #   :big_decimal, :fixnum, :integer, :float or :money
  # :money can only be specified if the Money gem is available to your application.
  config.price_type = :big_decimal
end

The latest eBay API version number can be found in the Trading API Release Notes.

Counting calls

As eBay limits the number of API calls that can be made each day, you may wish to keep track of your usage. You can provide an optional counter callback that will be called during each post.

Here is an example of how to use a Redis database to keep track of daily API calls.

config.counter = lambda {
    begin
      redis = Redis.new(host: 'localhost')
      key = "ebay_trader:production:call_count:#{Time.now.utc.strftime('%Y-%m-%d')}"
      redis.incr(key)
    rescue SocketError
      puts 'Failed to increment Redis call counter!'
    end
  }

Customizing request calls

EbayTrader::Request.new method accepts a Hash of options. Listed below are some of the common options.

Authentication token and site ID

An :auth_token and/or :ebay_site_id can be passed to each request, overriding any value defined in the module configuration.

request = EbayTrader::Request.new('GetItem', auth_token: ENV[EBAY_AUTH_TOKEN], ebay_site_id: 3) do
  CategorySpecific {
    CategoryID category_id_number
  }
end

Extending timeout

By default each request will allow up to 30 seconds (although this can be changed in the module configuration) before raising a timeout error. However some calls such as UploadSiteHostedPictures may require more time, especially if uploading large images. This timeout can be extended with the following option http_timeout: 60

Automatic type-casting

By default this gem tries to guess and auto-cast values to their appropriate types. As this is based on simple pattern recognition it does not always get it right. Take for example a call to GetUser. If an eBay user has the username ID '123456' this gem will type-cast the value to a Fixnum. This can be prevented by passing an array of keys to be excluded from type-casting to the Request constructor.

SKIP_TYPE_CASTING = [
        :charity_id,
        :city_name,
        :international_street,
        :phone,
        :postal_code,
        :name,
        :skype_id,
        :street,
        :street1,
        :street2,
        :user_id,
        :vat_id
    ]
    
request = EbayTrader::Request.new('GetUser', skip_type_casting: SKIP_TYPE_CASTING) do
  UserID user_id unless user_id.nil?
  ItemID item_id.to_s unless item_id.nil?
end

Known arrays

One of the limitations of XML is that it is not possible to explicitly define arrays. This means that when a response contains a list with only one element a parser cannot intrinsically determine that it should be an array. To overcome this limitation you can provide a list of known arrays to the request.

KNOWN_ARRAYS = [
        :compatibility,
        :copyright,
        :cross_border_trade,
        :discount_profile,
        :ebay_picture_url,
        :exclude_ship_to_location,
        :external_picture_url,
        :gift_services,
        :international_shipping_service_option,
        :item_specifics,
        :listing_enhancement,
        :name_value_list,
        :payment_allowed_site,
        :payment_methods,
        :promoted_item,
        :picture_url,
        :shipping_service_options,
        :ship_to_location,
        :ship_to_locations,
        :skype_contact_option,
        :tax_jurisdiction,
        :value,
        :variation,
        :variation_specific_picture_set,
        :variation_specifics,
        :variation_specifics_set
    ]
    
request = EbayTrader::Request.new('GetItem', known_arrays: KNOWN_ARRAYS) do
  ItemID item_id
  IncludeWatchCount true
  IncludeItemSpecifics true
  DetailLevel 'ItemReturnDescription' if include_description?
end  

Subsequently you can simply iterate over the data without having to first check if it is an array. This can also eliminate a post-processing step should you wish to dump the response hashes into mongoDB for analysis.

Cached responses

For testing and debugging you can inject a String containing the expected eBay response XML with the xml_response: xml_string option. If given this string will be parsed and no data will be posted to the eBay API.

Installation

Add this line to your application's Gemfile:

gem 'ebay_trader'

And then execute:

$ bundle

Or install it yourself as:

$ gem install ebay_trader

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake rspec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/altabyte/ebay_trading.

License

The gem is available as open source under the terms of the MIT License.