Pushrod

Old dogs, new tricks

A RubyonRails library for the ebay shopping API

with 21 comments


After the lightweight Facebook library I wrote to scratch my own itch, a couple of days ago I started to look at adding ebay items to Autopendium :: Stuff About Old Cars, the classic car website I run. Users were already shown books from Amazon, appropraite to the content being shown on the page, and it seemed to make sense to show models, cars and parts from ebay, for the vehicle or model being displayed.

Amazon books on Autopendium

I’d had a look at adding ebay functionality quite a while back, when I’d first just started to use Ruby and Rails, and couldn’t quite get to grips with ebay4r, which was at that time the ebay API ruby library. Since I’d last looked, another library had been written, Cody Fauser’s ebayapi, which he introduces with a brief tutorial here, and having a quick look at the code and the tests, it seemed just the job. I then fired up IRB and and gave it a test drive in the console.

It all seemed fine, just rather slow. The problem is, the library uses ebay’s SOAP interface, which is markedly slower than the REST one. And in fact, even the Trading REST interface is slower than the Shopping interface, as a quick and dirty benchmark shows:


  user       system       total      real
0.050000    0.030000    0.080000  (  6.487812) # 10 calls to the shopping REST API
0.130000    0.060000    0.190000  ( 12.517658) # 10 calls to the trading REST API

Now, if you want all the functionality that the Trading API provides — the ability to bid on items, or to list new items — that speed trade-off is no problem, as the user will expect such things to take a couple of seconds.

But if you’re wanting to include items for sale on a page each time it’s displayed (even allowing for caching), each 1/10th of a second counts, and the extra functionality that the Trading API provides is irrelevant.

Unfortunately, there’s no Ruby or Rails library for the Shopping API. So, time to scratch my own itch again. Enter ebay-shopping, a RubyonRails plugin for the ebay Shopping API. It’s a pretty straightforward plugin that was fairly easy to write (the first version, implemented as a basic lib file, was done in an afternoon), and is even easier to use.

To install, from the root of your rails app simply run the usual

script/plugin install http://ebay-shopping.googlecode.com/svn/trunk/ ebay_shopping

Then run

ruby vendor/plugins/ebay_shopping/install.rb

This will copy a basic configuration file into your app’s config directory. This is where you put your ebay settings (Ebay Application id, affiliate info if you have it, etc). Update this with your settings — the only thing you actually need is the app id, which you can get by signing up at http://developer.ebay.com (The code you need is called the AppID — the Auth Token and other stuff is for the Trading API).

Then fire up the Rails console and away we go:


>> request = EbayShopping::Request.new(:find_items, :query_keywords=>"Cadillac")
=> #<EbayShopping::Request:0x246aa54 @affiliate_shopper_id="my_campaign", @affiliate_partner="1",
@site_id=nil,@affiliate_id="foo1234bar", @callname=:find_items, @call_params={:query_keywords=>"Cadillac"},
@app_id="my_ebay_app_id_1234567">

>> response = request.response
=> #<EbayShopping::FindItemsResponse:0x2444520 @request=#<EbayShopping::Request:0x244a36c,
@url="http://open.api.ebay.com/shopping?version=547&appid=my_ebay_app_id_1234567&callname=FindItems&QueryKeywords=Cadillac",
@affiliate_shopper_id="my_campaign", @affiliate_partner="1", @site_id=nil, @affiliate_id=nil, @callname=:find_items,
@call_params={:query_keywords=>"Cadillac"}, @app_id="my_ebay_app_id_1234567",
@full_response={"Version"=>"547", "Timestamp"=>"2008-01-13T13:20:27.641Z", "Build"=>"e547_core_Bundled_5879814_R1",
"Item"=>[{"ShippingCostSummary"=>{"ShippingType"=>"NotSpecified"}, "ListingStatus"=>"Active", "TimeLeft"=>"P20DT16H59M6S",
"PrimaryCategoryName"=>"eBay Motors:Cars & Trucks:Cadillac:STS", "Title"=>"Cadillac : STS",
..."ItemSearchURL"=>"http://search.ebay.com/ws/search/SaleSearch?fsoo=2&fsop=1&satitle=Cadillac",
"Ack"=>"Success", "TotalItems"=>"15580", "xmlns"=>"urn:ebay:apis:eBLBaseComponents"}>

>> response.total_items
=> 15580

To get the items from the response, just ask for them


>> first_item = response.items.first
#<EbayShopping::Item:0x2413a88 @gallery_url="http://thumbs.ebaystatic.com/pict/230212386614.jpg",
@all_params={"ShippingCostSummary"=>{"ShippingType"=>"NotSpecified"}, "ListingStatus"=>"Active",
"TimeLeft"=>"P20DT16H59M6S", "PrimaryCategoryName"=>"eBay Motors:Cars & Trucks:Cadillac:STS",
"Title"=>"Cadillac : STS", "ConvertedCurrentPrice"=>{"currencyID"=>"USD", "content"=>"9500.0"},
"GalleryURL"=>"http://thumbs.ebaystatic.com/pict/230212386614.jpg", "ItemID"=>"230212386614",
"ListingType"=>"FixedPriceItem", "EndTime"=>"2008-02-03T06:19:33.000Z", "PrimaryCategoryID"=>"124117",
"ViewItemURLForNaturalSearch"=>"http://cgi.ebay.com/Cadillac-STS_W0QQitemZ230212386614QQcategoryZ124117QQcmdZViewItem"},
@view_item_url_for_natural_search="http://cgi.ebay.com/Cadillac-STS_W0QQitemZ230212386614QQcategoryZ124117QQcmdZViewItem",
@end_time="2008-02-03T06:19:33.000Z", @primary_category_name="eBay Motors:Cars & Trucks:Cadillac:STS",
@converted_current_price={"currencyID"=>"USD", "content"=>"9500.0"}, @title="Cadillac : STS",
@item_id="230212386614", @time_left="P20DT16H59M6S">

The key attributes for the item are available through ruby-ized version of the ebay Attributes (full documentation for the Shopping API calls and responses)


>> first_item.title # for the Title attribute
=> "Cadillac : STS"
>> first_item.gallery_url # for the GalleryURL attribute
=> "http://thumbs.ebaystatic.com/pict/230212386614.jpg"
>> first_item.view_item_url_for_natural_search # for the ViewItemURLForNaturalSearch attribute
=> "http://cgi.ebay.com/Cadillac-STS_W0QQitemZ230212386614QQcategoryZ124117QQcmdZViewItem"
>> first_item.bid_count
=> nil
>> first_item.primary_category_name
=> "eBay Motors:Cars & Trucks:Cadillac:STS"

As you can see, most of these responses are just strings. For the price, you’ve got a couple of options


>> first_item.converted_current_price
=> #<EbayShopping::Money:0x1410b70 @content=9500.0, @currency_id="USD">
>> first_item.converted_current_price.content
=> 9500.0

or


>> first_item.converted_current_price.to_s
=> "$9500.00"

It’s also worth noting the end time is returned as a Ruby Time object, so you can do calculations against it


>> first_item.end_time
=> Sun Feb 03 06:19:33 GMT 2008
>> first_item.end_time.class
=> Time

Finally, there’s a catch_all [] method which allows you to access other attributes using a familiar hash key notation:


>> first_item["ShippingCostSummary"]
=> {"ShippingType"=>"NotSpecified"}

Other methods and usage are given in the code comments and the fairly extensive test suite (browse the source here). There are also hooks to allow for caching and (separately) error caching, which is necessary if you want to get your app approved as a Compatible Application, which allows you a greater number of API calls per day (I did). I’ll post on usage of these and examples if anyone wants me to.

Tie that into your Rails app, and you’ve got an instant mash-up:
Ebay items on Autopendium

At the moment, the library’s only available as a RubyonRails plugin, rather than a Ruby gem. The only reason for this is that it was extracted from a Rails app, and is slightly structured accordingly (e.g. the YAML config file, and option for different settings in different environments). However, it’s probably not a huge job to package it as a gem, or to use the code as is in a standalone Ruby app.

p.s. Some of the less frequently used API calls haven’t yet been implemented, but are being done bit by bit, and if anyone’s got a crushing need for one of the missing ones, let me know, and I’ll bump it up the priority list.

About these ads

Written by ctagg

January 13, 2008 at 5:47 pm

21 Responses

Subscribe to comments with RSS.

  1. Thanks for sharing this plugin with the RoR community. Looking forward to using it tonight on my site.

    Scott

    February 16, 2008 at 5:40 am

  2. Thanks for publishing this. Is there a limit of 3 items in the response? I don’t see where this is specified, but even though the total_items shows thousands, I’m only getting 3 items.

    Tom

    February 20, 2008 at 12:26 am

  3. Tom
    3 is the default number of items returned by #find_items (see the Ebay shopping API docs: http://developer.ebay.com/DevZone/shopping/docs/CallRef/FindItems.html).

    You can actually get as many as 50 per request using the MaxEntries input parameter. So if you wanted 20 items returned you do something like this:

    request = EbayShopping::Request.new(:find_items, :query_keywords=>”Cadillac”, :max_entries => 20)

    Any of the input params can be submitted in the usual ruby hash. So the standad call I use all the time looks like this:
    request = EbayShopping::Request.new(:find_items_advanced, {
    :query_keywords => params[:term],
    :site_id => params[:site_id],
    :page_number => params[:page],
    :max_entries => params[:max_entries],
    :category_ID => params[:category_ID]})

    Hope this helps,
    Chris

    autopendium

    February 20, 2008 at 8:55 am

  4. Hi, I am trying to install your plugin and am getting this error:
    $ script/plugin install http://ebay-shopping.googlecode.com/svn/trunk ebay_shopping
    + ./trunk/CHANGELOG
    + ./trunk/LICENSE
    + ./trunk/README
    + ./trunk/Rakefile
    + ./trunk/ebay.yml.tpl
    + ./trunk/init.rb
    + ./trunk/install.rb
    + ./trunk/lib/ebay_shopping.rb
    + ./trunk/test/ebay_shopping_test.rb
    + ./trunk/test/xml_responses/ebay_error.xml
    + ./trunk/test/xml_responses/ebay_find_items.xml
    + ./trunk/test/xml_responses/ebay_find_items_advanced.xml
    + ./trunk/test/xml_responses/ebay_find_popular_items.xml
    + ./trunk/test/xml_responses/ebay_find_products.xml
    + ./trunk/test/xml_responses/ebay_get_category_info.xml
    + ./trunk/test/xml_responses/ebay_get_multiple_items.xml
    + ./trunk/test/xml_responses/ebay_get_single_item.xml
    + ./trunk/test/xml_responses/ebay_no_results.xml
    + ./trunk/test/xml_responses/ebay_request_error.xml
    + ./trunk/test/xml_responses/ebay_system_error.xml
    + ./trunk/test/xml_responses/ebay_timeout_error.xml
    Plugin not found: ["http://ebay-shopping.googlecode.com/svn/trunk", "ebay_shopping"]
    $

    Any thoughts?

    Mike

    April 9, 2008 at 4:43 pm

  5. So… to resolve my above issue… the plugin was getting installed into a trunk directory. I just renamed that to ebay_shopping. Good to go.

    Also… for future users… the AppId it turns out must be a production generated AppId not a sandbox AppId.

    These two issues resolved it seems I can search on Cadillacs. :)

    Mike

    April 9, 2008 at 5:12 pm

  6. This is great stuff – a lovely bit of code, and rather less of a footprint than Cody’s fabulously comprehensive gem.

    Thanks!

    Andy

    Andy Triggs

    April 29, 2008 at 9:33 pm

  7. Andy: Glad you like it. Got a couple of improvements I want to make, and may release it as a gem — just a matter of finding a bit of time…

    autopendium

    April 29, 2008 at 10:31 pm

  8. [...] I’ve jumped on the Git bandwagon, and to celebrate have made the ebay_shopping plugin (a ruby on rails library for eBay’s shopping API) into a gem, hosted at Github. It’ll take a few days before the rubyforge project is approved [...]

  9. Been using this plugin for a few months now (earned $137). However, it will probably stop working after May 31st because ebay is moving away from Commission Junction. The URL returned by Item.view_item_url_for_natural_search will have the old information for CJ.

    Have any of you already made the transition away from Commission Junction? What changes did you make (if any)?

    Scott

    May 22, 2008 at 5:33 am

  10. For the time being, I’ve hard-coded the new URL with the ebay item ID added at the end:

    This isn’t elegant, but it gets the job done. I’d still be interested to hear what the rest of you have done.

    You can view the code in action at my gardening website.

    Scott

    May 22, 2008 at 6:28 am

  11. And the code…

    link_to(item.title, ‘http://rover.ebay.com/rover/1/711-53200-19255-0/1?type=2&campid=5335917691&toolid=10001&customid=&ext=270237622242&item=’ + item.item_id)

    Scott

    May 22, 2008 at 6:30 am

  12. Scott
    Have a look at this post re ebay’s move away from Commission Junction:

    http://pushrod.wordpress.com/2008/04/04/the-ebay-shopping-api-and-the-new-ebay-affiliate-scheme/

    Should be straightforward. Works for me. Let me know if you have any probs.
    Chris

    autopendium

    May 22, 2008 at 7:51 pm

  13. hello,

    thanks for this plugin.
    but i have some trouble to use it.
    i get a RequestError, ApplicationID invalid. i use for this my sandbox ebay developer application id. i also tried the production id, but nothing works, who can help me?
    EbayShopping::Request.config_params({:app_id => “”, :default_site_id =>”77″}), is there something missing ?

    thanks alex

    alexbo

    May 27, 2008 at 12:40 pm

  14. in app_id => “myappid”

    alexbo

    May 27, 2008 at 1:04 pm

  15. alexbo
    Are you using the original plugin (from http://code.google.com/p/ebay-shopping/) or the gem, from Github?

    autopendium

    May 27, 2008 at 2:37 pm

  16. at the end it was my fault. i have to you use the production key, not the sandbox key.
    after this it works for me.

    thanks for this plugin, do you know if there is any possibility to specify the category in which the request will made ?!

    thanks

    alexbo

    May 28, 2008 at 8:01 am

  17. Yes, choosing the category is no problem, if you use find_items_advanced, which allows you to specify the category_id, and a whole host of other params. You can do something like to specify each of these:

    EbayShopping::Request.new(:find_items_advanced, { :query_keywords => params[:term],
    :site_id => params[:site_id],
    :page_number => params[:page],
    :max_entries => params[:max_entries],
    :category_ID => params[:category_ID]})

    For more details see the API info for FindItemsAdvanced: http://developer.ebay.com/DevZone/shopping/docs/CallRef/FindItemsAdvanced.html

    One possible gotcha is the category_ID is specific to each country (i.e. eBay US car parts category_ID is different from that for eBay Germany), so if you use items from several different eBay sites you need some sort of lookup table (I just use a constant defined in the environment file)

    autopendium

    May 28, 2008 at 8:31 am

  18. Hi,

    thanks for this great code!

    I tried to receive a list of items with listing status “Completed” like this:

    request = EbayShopping::Request.new(:find_items, :query_keywords=>”Cadillac”, :listing_status => “Closed”)

    Unfortunatelly, it did not deliver the expected result. What am I doing wrong?

    Thanks for your help.

    Kind regards,
    boris

    Boris

    September 14, 2008 at 4:59 pm

  19. All I can say is… huuuge thanks :) If I wasnt such a rails-n00b I’d have my app live tonight already thanks to you.

    Mark C

    January 22, 2009 at 12:21 pm

  20. Hi, is anyone else seeing their apps throw errors recently? I think it’s because eBay have added a “depracated” message to the responses.

    Mark C

    August 30, 2009 at 1:25 am

    • I’m not seeing any probs. Can you give a same of request and response?

      ctagg

      August 30, 2009 at 7:39 am


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: