Skip to content
Menu
Justin Ball
  • About
  • Privacy Policy
Justin Ball

Amazon Wishlist RSS, Ruby and Signing/Authenticating your Requests

Posted on September 2, 2009November 1, 2021

UPDATE: If you don’t want to bother with the code and instead would just like to get your Amazon.com Wishlist rss you can go here.

I’ve been playing with the Amazon API lately. At first I just wanted to get the RSS feed to my wish list and I followed the direction in this article on the Amazon developer site. Don’t bother with that article. This one on xml.com is a bit out of date, but still useful. Getting the RSS feed for your profile on most sites is a pretty simple process. On Amazon it’s not. It’s a total pain in the butt. Shame on them for not making this process easier. I shouldn’t have to interact with a full API just to gain access to an RSS feed. Also, for any Amazon people out there would you mind keeping your documentation up to date or at least marking old articles as invalid so that I don’t waste my time with stuff that doesn’t work anymore?</rant>.

OK so you don’t actually care about all the crap you just want the guts. I took the basic structure from ruby-aaws. Look there if you want a complete library. Here’s how to sign your Amazon requests using ruby code.



require 'rubygems'
require 'openssl'

class Amazon

  # Do we have support for the SHA-256 Secure Hash Algorithm?
  # Note that Module#constants returns Strings in Ruby 1.8 and Symbols in 1.9.
  DIGEST_SUPPORT = OpenSSL::Digest.constants.include?('SHA256') || OpenSSL::Digest.constants.include?(:SHA256)

  # Requests are authenticated using the SHA-256 Secure Hash Algorithm.
  DIGEST = OpenSSL::Digest::Digest.new('sha256') if DIGEST_SUPPORT

  AMAZON_SITES = {
    :ca => 'http://ecs.amazonaws.ca/onca/xml',
    :de => 'http://ecs.amazonaws.de/onca/xml',
    :fr => 'http://ecs.amazonaws.fr/onca/xml',
    :jp => 'http://ecs.amazonaws.jp/onca/xml',
    :uk => 'http://ecs.amazonaws.co.uk/onca/xml',
    :us => 'http://ecs.amazonaws.com/onca/xml'
  }

  # Sign an amazon query
  # Requires openssl and that GlobalConfig.amazon_secret_access_key be defined.
  # Based on ruby-aaws and documentation here
  # http://www.caliban.org/ruby/ruby-aws/
  # http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?RequestAuthenticationArticle.html
  # Parameters
  # query:    The query to be signed
  # locale:   Locale for the specific amazon site to use valid values are ca, de, fr, jp, uk, us
  def self.sign_query(uri, query, amazon_secret_access_key, locale = :us)
    raise 'SHA-256 not available in this version of openssl.  Cannot sign Amazon requests.' unless DIGEST_SUPPORT
    query << "&Timestamp=#{Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')}"
    new_query = query.split('&').collect{|param| "#{param.split('=')[0]}=#{url_encode(param.split('=')[1])}"}.sort.join('&')
    to_sign = "GET\n%s\n%s\n%s" % [uri.host, uri.path, new_query]
    hmac = OpenSSL::HMAC.digest(DIGEST, amazon_secret_access_key, to_sign)
    base64_hmac = [hmac].pack('m').chomp
    signature = url_encode(base64_hmac)
    new_query << "&Signature=#{signature}"
  end

  # Encode a string, such that it is suitable for HTTP transmission.
  def self.url_encode(string)
    # Shamelessly plagiarised from Wakou Aoyama's cgi.rb, but then altered slightly to please AWS.
    string.gsub( /([^a-zA-Z0-9_.~-]+)/ ) do
      '%' + $1.unpack( 'H2' * $1.bytesize ).join( '%' ).upcase
    end
  end

end

</pre>

I put together another class to make the requests:

require 'rubygems'
require 'httparty'
class AmazonRequest
  include HTTParty
  format :xml

  # Initialize Amazon Request.  Obtain valid Amazon credentials from your developer account
  # Parameters:
  # amazon_access_key_id:     Valid Amazon access key
  # amazon_secret_access_key: Valid Amazon secret access key
  # amazon_associate_tag:     Valid Amazon associates tag (optional)
  # locale:                   Locale for the specific amazon site to use valid values are :ca, :de, :fr, :jp, :uk, :us (optional, default is us)
  def initialize(amazon_access_key_id, amazon_secret_access_key, amazon_associate_tag = nil, locale = :us)
    @amazon_access_key_id = amazon_access_key_id
    @amazon_secret_access_key = amazon_secret_access_key
    @amazon_associate_tag = amazon_associate_tag
    @locale = locale
  end

  # Generate rss feeds for the give email
  # Parameters:
  # email:    email for which to find feeds.
  def get_amazon_feeds(email)
    wishlists = get_customer_wishlists(email)
    if !wishlists.blank?
      wishlist_ids = wishlists.collect{|list| list['ListId']}
      generate_wishlist_rss(wishlist_ids)
    end
  end

  # Get matching id for the given email
  # Parameters:
  # email:  customer's email.
  def get_customer_id(email)
    query = "Operation=CustomerContentSearch&Email=#{email}"
    result = make_request(query)
    if result['CustomerContentSearchResponse']['Customers']['TotalResults'].to_i > 0
      result['CustomerContentSearchResponse']['Customers']['Customer'][0]
    end
  end

  # Get information for the given customer id
  def get_customer_information(customer_id)
    query = "Operation=CustomerContentLookup&ResponseGroup=CustomerLists&CustomerId=#{customer_id}"
    make_request(query)
  end

  # Get customer's wishlist ids
  def get_customer_wishlists(email)
    query = "Operation=ListSearch&ListType=WishList&Email=#{email}"
    result = make_request(query)
    result['ListSearchResponse']['Lists']['List']
  end

  def generate_wishlist_rss(wishlist_ids)
    feeds = []
    wishlist_ids.each do |wishlist_id|
      query = "Operation=ListLookup&ListType=WishList&ListId=#{wishlist_id}&ResponseGroup=ItemAttributes,ListItems,ListInfo,Offers&Sort=DateAdded&Style=#{Amazon::ECS_TO_RSS_WISHLIST}"
      feeds << make_xslt_request(query)
    end
    feeds
  end

  protected
    def make_request(query)
      add_required_params(query)
      uri = Amazon::AMAZON_SITES[@locale]
      signed_query = Amazon.sign_query(URI.parse(uri), query, @amazon_secret_access_key)
      AmazonRequest.get(uri, :query => signed_query)
    end

    def make_xslt_request(query)
      add_required_params(query)
      uri = Amazon::AMAZON_XSLT_SITES[@locale]
      signed_query = Amazon.sign_query(URI.parse(uri), query, @amazon_secret_access_key)
      "#{uri}?#{signed_query}"
    end

    def add_required_params(query)
      query << "&Service=AWSECommerceService"
      query << "&AWSAccessKeyId=#{@amazon_access_key_id}"
      query << "&AssociateTag=#{@amazon_associate_tag}" if @amazon_associate_tag
      query << "&Version=2009-07-01"
    end
end
</pre>

And finally make the calls:


amazon_associate_tag = 'jbasdf-20' # feel free to use my associate tag :-)
amazon_secret_access_key = 'your secret key'
amazon_access_key_id = 'your access key'
email = '[email protected]' # put a valid Amazon email here

am = AmazonRequest.new(amazon_access_key_id, amazon_secret_access_key, amazon_associate_tag)
puts am.get_amazon_feeds(email)
</pre>

This will give you a list of wishlist RSS feeds.

That was way to freakin' hard for something so simple.  Amazon gets an 'F'.

Leave a Reply Cancel reply

You must be logged in to post a comment.

Recent Posts

  • Around and Back to WordPress
  • Last Lagoon (This Year)
  • Logan Sunset
  • Grami Del
  • FanX (and Lagoon)

Recent Comments

  1. Around and Back to WordPress – Justin Ball on Gatsby 2.0 and Forestry
  2. More Stuff You Shouldn’t Hit on a Bike – Justin Ball on Why Cyclists Shave Their Legs. The Most Disgusting Post I Will Ever Make
  3. First Real Ride on the New Trek Madone 6.9 – Justin Ball on Rode Blacksmith Fork Canyon Tonight
  4. First ride up Black Smith Fork canyon this season – Justin Ball on Why Cyclists Shave Their Legs. The Most Disgusting Post I Will Ever Make
  5. How New Carpet and Rattlesnake turned me into a Consultant or What the Hell Happened? – Justin Ball on Why Cyclists Shave Their Legs. The Most Disgusting Post I Will Ever Make

Archives

  • November 2021
  • October 2021
  • September 2021
  • January 2020
  • February 2018
  • January 2018
  • December 2017
  • November 2017
  • October 2017
  • February 2017
  • November 2016
  • September 2016
  • August 2016
  • May 2016
  • March 2016
  • February 2016
  • November 2015
  • September 2015
  • June 2015
  • May 2015
  • February 2015
  • January 2015
  • October 2014
  • September 2014
  • July 2014
  • June 2014
  • May 2014
  • April 2014
  • March 2014
  • February 2014
  • January 2014
  • December 2013
  • October 2013
  • September 2013
  • August 2013
  • June 2013
  • May 2013
  • April 2013
  • February 2013
  • January 2013
  • December 2012
  • October 2012
  • September 2012
  • June 2012
  • January 2012
  • December 2011
  • September 2011
  • August 2011
  • July 2011
  • June 2011
  • May 2011
  • March 2011
  • February 2011
  • January 2011
  • December 2010
  • November 2010
  • September 2010
  • August 2010
  • July 2010
  • June 2010
  • May 2010
  • March 2010
  • February 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • August 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009
  • March 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • October 2008
  • September 2008
  • August 2008
  • July 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • November 2007
  • October 2007
  • September 2007
  • August 2007
  • July 2007
  • June 2007
  • May 2007
  • March 2007
  • February 2007
  • January 2007
  • December 2006
  • November 2006
  • October 2006
  • September 2006
  • August 2006
  • July 2006
  • June 2006
  • May 2006
  • April 2006
  • March 2006
  • December 2005
  • November 2005
  • October 2005
  • September 2005

Categories

  • 2.3.2
  • 3g
  • 3tera
  • 420
  • 51weeks
  • 64bit
  • accessibility
  • ActionView::MissingTemplate
  • activemerchant
  • ActiveRecord
  • activesalesforce
  • acts as taggable
  • acts_as_facebook_user
  • acts_as_nested_set
  • acts_as_state_machine
  • advertising
  • Affiliate Marketing
  • air quality
  • ajax
  • Alyssa
  • ama
  • amazon
  • amazon s3
  • amazon wishlist
  • amazon.com
  • ancestry
  • animal cookies
  • antshares
  • apache
  • API
  • apis
  • apollo
  • apollo client
  • apple
  • Apple Store
  • Apple Time Capsule
  • application
  • applications
  • Art
  • ASP.Net
  • assert_sent_email
  • asyncronous processing
  • Atomic Jolt
  • Aubrey
  • Authentication
  • authorize.net
  • Autumn
  • babelphish
  • back problems
  • backbone.js
  • backup software
  • backups
  • bacon
  • Battlestar Galactica
  • big companies
  • birthday.
  • bitcoin
  • black cherry vanilla coke
  • Black Smith Fork Canyon
  • blockchain
  • blog
  • Blogging
  • bluehost
  • books
  • BoomStartup
  • bread
  • buddypress
  • bug
  • bugs
  • business
  • business. mother's animal cookies
  • cache county
  • cache valley
  • California
  • Cancun
  • canvas
  • capistrano
  • Catholic Church
  • cereal
  • chauvet obey 40
  • checkbox list
  • checkboxes
  • chess
  • Chicago
  • china
  • chocolate
  • Christmas
  • Chrome
  • church
  • Cinderella
  • Cisco
  • cloud computing
  • cms
  • code generation
  • code sprint
  • coke
  • Comcast
  • commerce
  • Common Lisp
  • communities
  • Community
  • complex
  • Computers
  • conference
  • conference software
  • configuration
  • consulting
  • cookies
  • cooking
  • COSL
  • cosmos
  • count
  • courts
  • cows
  • create
  • creative commons
  • cryptocurrencies
  • cryptography
  • css animations
  • cucumber
  • currency
  • Cycling
  • database
  • dataloader
  • date
  • death
  • death ray
  • debugging
  • decentralized applications
  • dell dimension 8400
  • democray
  • deployment
  • developing
  • development
  • Devin
  • diet
  • digg
  • Digital Ocean
  • digital-photography
  • disease
  • disguise
  • disgusting
  • disney
  • disneyland
  • DiSo
  • disposable
  • DMX
  • Docker
  • domain name
  • domains
  • doom
  • dr strangelove
  • driving
  • Dryers
  • DVI
  • ec2
  • economics
  • economy
  • ecto
  • edge rails
  • Education
  • EFF
  • Egypt
  • ElasticSearch
  • elastra
  • elections
  • elixir
  • email
  • Ember
  • Ember.js
  • encoding
  • energy
  • engine yard
  • engines testing
  • engineyard
  • enterprise
  • epp
  • error
  • errors
  • ethereum
  • Event Machine
  • expercom
  • facebook
  • failure
  • Family
  • family history
  • family reunion
  • family search
  • family trip
  • Family Vacation
  • familysearch
  • familysearch.org
  • farmers market
  • fashion
  • fences
  • field trip
  • file uploads
  • Firebase
  • fireeagle
  • fix
  • flat tax
  • flowers
  • folksonomy
  • food
  • France iPad Internet access
  • free book
  • freedom
  • friendfeed
  • friends
  • fuel
  • Fun Stuff
  • funeral
  • Funny
  • funny kids
  • gadgets
  • galleries
  • gamenight
  • garden
  • gardens
  • garter snake
  • gatsby
  • gatsbyjs
  • gearsynper
  • geek
  • gelatin
  • gem
  • gems
  • gems ruby on rails
  • genealogy
  • genius
  • geocaching
  • geotagging
  • girl's camp
  • gistr
  • git
  • github
  • global
  • gmail
  • godaddy
  • Goliath
  • Google
  • google bomb
  • google docs
  • google hacks
  • Gorden B Hinckley
  • government
  • gps
  • grand master
  • grand-teton-national-park
  • graph ql
  • graphcool
  • graphql
  • graphqlsummit
  • great firewall
  • grocery
  • gross
  • group work
  • HABTM
  • Hacks
  • halloween
  • happy
  • has and belongs to many
  • has_many
  • hashgraph
  • Hawaii
  • health
  • health insurance
  • heirachy
  • Heirarchies
  • helps
  • Heroku
  • Holiday
  • home building
  • home improvement
  • home plans
  • homebrew
  • homework
  • hosting
  • house plans
  • House Stuff
  • housing
  • human rights
  • hyperledger
  • i18n
  • ice cream
  • icls2008
  • idaho
  • ideas
  • identity
  • identity_theft
  • iiw2006b
  • image
  • image processing
  • inbox
  • induglences
  • insane
  • inspiration
  • install
  • Instructure
  • Interesting
  • internet
  • Internet Explorer
  • InvalidAuthenticityToken
  • iPhone
  • jackson-hole
  • jamis buck
  • Javascript
  • JavaScript (Programming Language)
  • Javscript
  • Jenna
  • jeweler
  • jobs
  • joyent
  • jQuery
  • jungle disk
  • jurlp
  • justin ball
  • kids
  • knowledge workers
  • lambad
  • laptop case
  • launchup.org
  • lds
  • LDS church
  • learning
  • legal
  • Lego
  • legos
  • leopard
  • lesson
  • Levi Leipheimer
  • Liahona
  • library
  • life
  • lifestream
  • Links
  • litecoin
  • LMS
  • loans
  • localization
  • logan
  • Logan Canyon
  • logistics
  • logitech
  • LTI
  • lucene
  • lucene.net
  • Lucifer
  • luvfoo
  • mac
  • Mac OSX 10.6
  • Mac Ports
  • macbook
  • macbook pro
  • Maker
  • Maker Faire
  • manage
  • marginal changes
  • marion
  • marriage
  • Matt Mullenweg
  • me
  • medicine
  • Meetings
  • merb
  • Mexico
  • micro-blogging
  • microcontent
  • microformats
  • Microsoft
  • Middle East
  • migrations
  • mom
  • money
  • Monitor
  • morph
  • morph exchange
  • morphexchange
  • mortgage
  • mosso
  • motorcycle
  • mountain biking
  • Mountain West Javascript
  • Mountain West Ruby
  • mountain west ruby conference
  • mountainwestrubyconf
  • mozy
  • MRI
  • mtnwestrubyconf
  • muck
  • multi-user
  • music
  • mwjs
  • mwrc
  • mysql
  • mysql gem
  • MYTecC
  • Neat Stuff
  • neighbors
  • newgem
  • No Programming
  • node.js
  • nuclear weapons
  • nutcracker
  • Oahu
  • Oauth
  • oauth-plugin
  • Obama
  • Obie Fernandez
  • OER
  • OER Glue
  • olympic torch
  • olympics
  • omniauth
  • Open Assessments
  • open source
  • OpenContent
  • opened2007
  • OpenID
  • opensocial
  • optimism
  • ordered tree
  • oreos
  • osx
  • outdoors
  • outsourcing
  • ozmozr
  • pain
  • panasonic plasma
  • Paris
  • password recovery
  • payday lenders
  • paypal
  • pety
  • PGP
  • Phil Windley
  • photography
  • photoJAR
  • photos
  • php
  • pickle soup
  • pickup
  • piclens
  • Pictures
  • plasma tv
  • Playa Del Carmen
  • plugin
  • plugins
  • poinsettia
  • Political
  • politics
  • portablecontacts
  • PostGreSQL
  • PostGresSQL
  • poverty
  • privacy
  • problems
  • product: web
  • professional
  • Programming
  • Projects
  • prophet
  • protect_from_forgery
  • protests
  • prototype
  • psych
  • psychology
  • queue
  • rails
  • rails 2.0
  • rails conference
  • Rails I18n Textmate bundle
  • RailsConf
  • RailsConf07
  • rake
  • rant
  • react
  • react router
  • React.js
  • Reactive
  • reactjs
  • reactrouter
  • realestate
  • recipe
  • recommender
  • records
  • red green
  • redirect_to
  • regular expressions
  • relay
  • religion
  • render
  • replace
  • reputation
  • require.js
  • research
  • REST
  • restaurant
  • rFacebook
  • ridiculous
  • rightscale
  • ringside networks
  • river
  • river trail
  • robots
  • romantic
  • roomba
  • rpsec
  • rspec
  • rspec bundle
  • rss
  • ruby
  • Ruby On Rails
  • Ruby On Railst
  • ruby_on_rails
  • rvm
  • s3
  • sad
  • Salesforce
  • samsung ml1740
  • sarah sample
  • scalability
  • School
  • Science
  • scorm
  • scream
  • script.aculo.us
  • SDK
  • search
  • senate
  • SEO
  • serverless
  • servers
  • sessions
  • shopping
  • shortcodes
  • shoulda
  • sign language
  • simple
  • small business
  • snakes
  • Snelgrove
  • social graph
  • social media
  • social network dilution
  • social networking
  • social search
  • Social Software
  • socialsoftware
  • society2.0
  • soda
  • software
  • software design
  • Software Development
  • solidity
  • solo
  • soviet union
  • sovrin
  • sql
  • sql server
  • SQL Server 2005 Express
  • sql server 2008 express
  • starling
  • start ups
  • startups
  • starvation
  • stm bags
  • stm medium alley
  • storage
  • subversion
  • target
  • tax
  • Teachers Without Borders
  • tech
  • teeth whitening
  • template not foudn
  • templates
  • test-spec
  • testing
  • tests
  • textmate
  • thanksgiving point
  • The Japanese Mafia is controlling the weather
  • The Kids
  • The Plan Collection
  • The Web
  • theming skin
  • theplancollection
  • theplancollection.com
  • time
  • timr
  • tips
  • to_json
  • tools
  • Tour de France
  • transfer
  • translations
  • Travel
  • Travel, Disneyland, LA
  • trees
  • trip
  • truffles
  • tutorial
  • tutorials
  • tv
  • twitter
  • Uncategorized
  • uninsured
  • universe
  • unpack
  • unread
  • upgrades
  • uploader
  • uploads
  • user discovery
  • user interface
  • userfly
  • utah
  • utah government
  • utah senate
  • utf8
  • Vacation
  • values
  • vinegar
  • virtual hosts
  • walmart
  • warranty
  • Waste of Time
  • weather
  • Web
  • web design
  • web development
  • Web RTC
  • Web2.0
  • web2con2006
  • webservices
  • weddings
  • Wesley Connell
  • whereigo
  • wife
  • windows
  • Wired
  • wishlist
  • with
  • word press
  • Wordpress
  • work
  • workling
  • wpmu
  • xml
  • yeast
  • yellowstone
  • zentest
©2023 Justin Ball | Powered by SuperbThemes & WordPress