Module: ASIN::Client

Defined in:
lib/asin/client.rb

Constant Summary collapse

DIGEST =
OpenSSL::Digest::Digest.new('sha256')
PATH =
'/onca/xml'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.instanceObject

Convenience method to create an ASIN client.

An instance is not necessary though, you can simply include the ASIN module otherwise.



111
112
113
114
115
# File 'lib/asin/client.rb', line 111

def self.instance
  ins = Object.new
  ins.extend ASIN::Client
  ins
end

Instance Method Details

#add_items(cart, *items) ⇒ Object

Performs an CartAdd REST call against the Amazon API.

Expects a SimpleCart created with create_cart and one ore more Item-Hashes and returns an updated SimpleCart:

cart = add_items(cart, {:asin => '1430216263', :quantity => 2})

Options:

Additional parameters for the API call like this:

add_items(cart, {:asin => '1430218150', :quantity => 1}, {:asin => '1430216263', :quantity => 1, :action => :SaveForLater})

Have a look at the different cart item operation values on the Amazon-Documentation



261
262
263
# File 'lib/asin/client.rb', line 261

def add_items(cart, *items)
  cart(:CartAdd, create_item_params(items).merge({:CartId => cart.cart_id, :HMAC => cart.hmac}))
end

#arrayfy(item) ⇒ Object



295
296
297
298
# File 'lib/asin/client.rb', line 295

def arrayfy(item)
  return [] unless item
  item.is_a?(Array) ? item : [item]
end

#browse_node(node_id, params = {:ResponseGroup => :BrowseNodeInfo}) ⇒ Object

Performs an BrowseNodeLookup REST call against the Amazon API.

Expects a Hash of search params where and returns a SimpleNode:

node = browse_node '163357'

Options:

Additional parameters for the API call like this:

browse_node('163357', :ResponseGroup => :TopSellers)

Have a look at the different browse node values on the Amazon-Documentation



214
215
216
217
# File 'lib/asin/client.rb', line 214

def browse_node(node_id, params={:ResponseGroup => :BrowseNodeInfo})
  response = call(params.merge(:Operation => :BrowseNodeLookup, :BrowseNodeId => node_id))
  [handle_type(response['BrowseNodeLookupResponse']['BrowseNodes']['BrowseNode'], Configuration.node_type),response]
end

#call(params) ⇒ Object



342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/asin/client.rb', line 342

def call(params)
  Configuration.validate_credentials!
 params[:ResponseGroup] = params[:ResponseGroup].collect{|g| g.to_s.strip}.join(',') if !params[:ResponseGroup].nil? && params[:ResponseGroup].is_a?(Array)
  log(:debug, "calling with params=#{params}")
  signed = create_signed_query_string(params)

  url = "http://#{Configuration.host}#{PATH}?#{signed}"
  log(:info, "performing rest call to url='#{url}'")

  response = HTTPI.get(url)
  if response.code == 200
    # force utf-8 chars, works only on 1.9 string
    resp = response.body
    resp = resp.force_encoding('UTF-8') if resp.respond_to? :force_encoding
    log(:debug, "got response='#{resp}'")
    Crack::XML.parse(resp)
  else
    log(:error, "got response='#{response.body}'")
    raise "request failed with response-code='#{response.code}'"
  end
end

#cart(operation, params = {}) ⇒ Object



336
337
338
339
340
# File 'lib/asin/client.rb', line 336

def cart(operation, params={})
  response = call(params.merge(:Operation => operation))
  cart = response["#{operation}Response"]['Cart']
  handle_type(cart, Configuration.cart_type)
end

#clear_cart(cart) ⇒ Object

Performs an CartClear REST call against the Amazon API.

Expects a SimpleCart created with create_cart and returns an empty SimpleCart:

cart = clear_cart(cart)


289
290
291
# File 'lib/asin/client.rb', line 289

def clear_cart(cart)
  cart(:CartClear, {:CartId => cart.cart_id, :HMAC => cart.hmac})
end

#configure(options = {}) ⇒ Object

Configures the basic request parameters for ASIN.

Expects at least secret and key for the API call:

configure :secret => 'your-secret', :key => 'your-key'

See ASIN::Configuration for more infos.



125
126
127
# File 'lib/asin/client.rb', line 125

def configure(options={})
  Configuration.configure(options)
end

#create_cart(*items) ⇒ Object

Performs an CartCreate REST call against the Amazon API.

Expects one ore more item-hashes and returns a SimpleCart:

cart = create_cart({:asin => '1430218150', :quantity => 1})

Options:

Additional parameters for the API call like this:

create_cart({:asin => '1430218150', :quantity => 1}, {:asin => '1430216263', :quantity => 1, :action => :SaveForLater})

Have a look at the different cart item operation values on the Amazon-Documentation



233
234
235
# File 'lib/asin/client.rb', line 233

def create_cart(*items)
  cart(:CartCreate, create_item_params(items))
end

#create_item_params(items) ⇒ Object



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/asin/client.rb', line 318

def create_item_params(items)
  keyword_mappings = {
    :asin               => 'ASIN',
    :quantity           => 'Quantity',
    :cart_item_id       => 'CartItemId',
    :offer_listing_id   => 'OfferListingId',
    :action             => 'Action'
  }
  params = {}
  items.each_with_index do |item, i|
    item.each do |key, value|
      next unless keyword = keyword_mappings[key]
      params["Item.#{i}.#{keyword}"] = value.to_s
    end
  end
  params
end

#create_query(params) ⇒ Object



387
388
389
390
391
392
# File 'lib/asin/client.rb', line 387

def create_query(params)
  params.map do |key, value|
    value = value.collect{|v| v.to_s.strip}.join(',') if value.is_a?(Array)
    "#{key}=#{CGI.escape(value.to_s)}"
  end.sort.join('&').gsub('+','%20') # signing needs to order the query alphabetically
end

#create_signed_query_string(params) ⇒ Object



364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/asin/client.rb', line 364

def create_signed_query_string(params)
  # nice tutorial http://cloudcarpenters.com/blog/amazon_products_api_request_signing/
  params[:Service] = :AWSECommerceService
  params[:AWSAccessKeyId] = Configuration.key

  params[:Version] = Configuration.version unless Configuration.blank? :version
  params[:AssociateTag] = Configuration.associate_tag unless Configuration.blank? :associate_tag

  # utc timestamp needed for signing
  params[:Timestamp] = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')

  
  query = create_query(params)

  # yeah, you really need to sign the get-request not the query
  request_to_sign = "GET\n#{Configuration.host}\n#{PATH}\n#{query}"
  hmac = OpenSSL::HMAC.digest(DIGEST, Configuration.secret, request_to_sign)

  # don't forget to remove the newline from base64
  signature = CGI.escape(Base64.encode64(hmac).chomp)
  "#{query}&Signature=#{signature}"
end

#get_cart(cart_id, hmac) ⇒ Object

Performs an CartGet REST call against the Amazon API.

Expects the CartId and the HMAC to identify the returning SimpleCart:

cart = get_cart('176-9182855-2326919', 'KgeVCA0YJTbuN/7Ibakrk/KnHWA=')


243
244
245
# File 'lib/asin/client.rb', line 243

def get_cart(cart_id, hmac)
  cart(:CartGet, {:CartId => cart_id, :HMAC => hmac})
end

#handle_item(item) ⇒ Object



300
301
302
# File 'lib/asin/client.rb', line 300

def handle_item(item)
  handle_type(item, Configuration.item_type)
end

#handle_type(data, type) ⇒ Object



304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/asin/client.rb', line 304

def handle_type(data, type)
  if type.is_a?(Class)
    type.new(data)
  elsif type == :mash
    require 'hashie'
    Hashie::Mash.new(data)
  elsif type == :rash
    require 'rash'
    Hashie::Rash.new(data)
  else
    data
  end
end

#log(severity, message) ⇒ Object



394
395
396
# File 'lib/asin/client.rb', line 394

def log(severity, message)
  Configuration.logger.send severity, message if Configuration.logger
end

#lookup(*asins) ⇒ Object

Performs an ItemLookup REST call against the Amazon API.

Expects an arbitrary number of ASIN (Amazon Standard Identification Number) and returns an array of SimpleItem:

item = lookup '1430218150'
item.title
=> "Learn Objective-C on the Mac (Learn Series)"
items = lookup ['1430218150', '0439023521']
items[0].title
=> "Learn Objective-C on the Mac (Learn Series)"
items[1].title
=> "The Hunger Games"

Options:

Additional parameters for the API call like this:

lookup(asin, :ResponseGroup => :Medium)

Or with multiple parameters:

lookup(asin, :ResponseGroup => [:Small, :AlternateVersions])


152
153
154
155
156
# File 'lib/asin/client.rb', line 152

def lookup(*asins)
  params = asins.last.is_a?(Hash) ? asins.pop : {:ResponseGroup => :Medium}
  response = call(params.merge(:Operation => :ItemLookup, :ItemId => asins.join(',')))
  [arrayfy(response['ItemLookupResponse']['Items']['Item']).map {|item| handle_item(item)},response]
end

#search(params = {:SearchIndex => :Books, :ResponseGroup => :Medium}) ⇒ Object

Performs an ItemSearch REST call against the Amazon API.

Expects a Hash of search params where and returns a list of SimpleItems:

items = search :SearchIndex => :Music

Options:

Additional parameters for the API call like this:

search(:Keywords => 'nirvana', :SearchIndex => :Music)

Have a look at the different search index values on the Amazon-Documentation



195
196
197
198
# File 'lib/asin/client.rb', line 195

def search(params={:SearchIndex => :Books, :ResponseGroup => :Medium})
  response = call(params.merge(:Operation => :ItemSearch))
  [arrayfy(response['ItemSearchResponse']['Items']['Item']).map {|item| handle_item(item)},response]
end

#search_keywords(*keywords) ⇒ Object

Performs an ItemSearch REST call against the Amazon API.

Expects a search-string which can be an arbitrary array of strings (ASINs f.e.) and returns a list of SimpleItems:

items = search_keywords 'Learn', 'Objective-C'
items.first.title
=> "Learn Objective-C on the Mac (Learn Series)"

Options:

Additional parameters for the API call like this:

search_keywords('nirvana', 'never mind', :SearchIndex => :Music)

Have a look at the different search index values on the Amazon-Documentation



174
175
176
177
178
179
# File 'lib/asin/client.rb', line 174

def search_keywords(*keywords)
  params = keywords.last.is_a?(Hash) ? keywords.pop : {:SearchIndex => :Books, :ResponseGroup => :Medium}
  response = call(params.merge(:Operation => :ItemSearch, :Keywords => keywords.join(' ')))
  
  [arrayfy(response['ItemSearchResponse']['Items']['Item']).map {|item| handle_item(item)},response]
end

#update_items(cart, *items) ⇒ Object

Performs an CartModify REST call against the Amazon API.

Expects a SimpleCart created with create_cart and one ore more Item-Hashes to modify and returns an updated SimpleCart:

cart = update_items(cart, {:cart_item_id => cart.items.first.CartItemId, :quantity => 7})

Options:

Additional parameters for the API call like this:

update_items(cart, {:cart_item_id => cart.items.first.CartItemId, :action => :SaveForLater}, {:cart_item_id => cart.items.first.CartItemId, :quantity => 7})

Have a look at the different cart item operation values on the Amazon-Documentation



279
280
281
# File 'lib/asin/client.rb', line 279

def update_items(cart, *items)
  cart(:CartModify, create_item_params(items).merge({:CartId => cart.cart_id, :HMAC => cart.hmac}))
end