Class: AmazonProductAdvertisingApi::Operations::Base::Request

Inherits:
Object
  • Object
show all
Defined in:
lib/amazon_product_advertising_api/operations/base.rb

Overview

This is the parent class of any Operations performed.

Each class should have a constant defined called REQUEST_PARAMETERS which contains the available parameters as defined in the API docs. Each class should also override the parse method with a custom version to suit the particular pattern of XML returned for it.

Subclasses should also override initialize to take any parameters the API defines as required, and follow the pattern of the region being the last parameter.

Before doing that though it should call super back to this one.

Constant Summary collapse

SERVICE_URLS =
{
    :us => 'http://ecs.amazonaws.com/onca/xml',
    :uk => 'http://ecs.amazonaws.co.uk/onca/xml',
    :ca => 'http://ecs.amazonaws.ca/onca/xml',
    :de => 'http://ecs.amazonaws.de/onca/xml',
    :jp => 'http://ecs.amazonaws.jp/onca/xml',
    :fr => 'http://ecs.amazonaws.fr/onca/xml'
}
API_VERSION =
"2009-01-06"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRequest

Returns a new instance of Request.



54
55
56
57
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 54

def initialize
  self.response = AmazonProductAdvertisingApi::Operations::Base::Element.new
  self.errors   = []
end

Instance Attribute Details

#errorsObject

Array of Struct - Any errors will be added to this attribute and each has an attribute of code or message.



41
42
43
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 41

def errors
  @errors
end

#hpricot_dataObject

Hpricot - This stores the raw data of the request response should you feel the need / desire to do some parsing yourself.



31
32
33
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 31

def hpricot_data
  @hpricot_data
end

#is_validObject

Boolean - All responses have a field saying whether the request was valid. Note that this refers to the format of the request, etc and not errors with the request parameters, etc. I.e. a lookup for an item that doesn’t exsist is still valid.



38
39
40
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 38

def is_valid
  @is_valid
end

#operationObject

String - The name of the Operation you want to perform, i.e. ItemSearch, ItemLookup, etc.



22
23
24
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 22

def operation
  @operation
end

#raw_dataObject

String - This stores the raw data of the request response (again, for investigation if you want to look under the covers).



28
29
30
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 28

def raw_data
  @raw_data
end

#regionObject

String - Amazon API calls can be sent to any of 6 regions, so this defines which one. It’ll also use this data to pick the right Associates key to use.



19
20
21
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 19

def region
  @region
end

#request_uriObject

String - This stores the request that gets sent to Amazon (for investigation if you want to look under the covers).



25
26
27
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 25

def request_uri
  @request_uri
end

#responseObject

Element - This is the root of the structure that the lib assembles from the data when parsed.



34
35
36
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 34

def response
  @response
end

Instance Method Details

#parseObject

The parse method of a request should be overwritted by any subclasses to account for different patterns in the XML.



109
110
111
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 109

def parse
  raise "This should be being overridden by it's subclass to provide custom parsing for the particular operation concerned."
end

#query_amazon(params) ⇒ Object

This takes care of building request, performing it, storing the results, checking for errors then parsing the data (if the request was valid).



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 60

def query_amazon(params)
  request_params = {}
  request_params["Service"]          = "AWSECommerceService"
  request_params["SignatureVersion"] = 2
  request_params["SignatureMethod"]  = "HmacSHA256"
  request_params["Timestamp"]        = Time.now.gmtime.iso8601
  request_params["AWSAccessKeyId"]   = AmazonProductAdvertisingApi::Base.access_key_id
  request_params["Operation"]        = self.operation
  request_params["AssociateTag"]     = AmazonProductAdvertisingApi::Base.associate_ids.send(self.region) unless AmazonProductAdvertisingApi::Base.associate_ids.send(self.region).nil?
  request_params["Version"]          = API_VERSION
  request_params.merge!(params)

  # Process all params - make sure they're all strings, camelize and escape (where appropriate)
  request_params = request_params.collect { |var, val| [var.to_s.camelize, val.to_s] }
  request_params = request_params.collect { |var, val| [var, CGI::escape(val).gsub('+', '%20')] }
  
  # Assemble into a full request string
  unsigned_uri = URI.parse("#{SERVICE_URLS[self.region]}?#{request_params.sort { |a, b| a[0] <=> b[0] }.collect { |var, val| var + "=" + val }.join("&")}")

  # Generate hmac
  hmac = HMAC::SHA256.new(AmazonProductAdvertisingApi::Base.secret_access_key)
  hmac.update("GET\n#{unsigned_uri.host}\n#{unsigned_uri.path}\n#{unsigned_uri.query}")

  self.request_uri = URI.parse("#{unsigned_uri}&Signature=#{CGI::escape(Base64.encode64(hmac.digest).chomp)}")

  result = Net::HTTP::get_response(self.request_uri)
  raise("Error connecting to Amazon - #{result.to_s}") if !result.kind_of?(Net::HTTPSuccess)
      
  # Store away the raw data for debugging or if more direct access is required
  self.raw_data     = result.body
  self.hpricot_data = Hpricot.XML(self.raw_data)
      
  # Now parse the xml and build out the reponse elements
  self.is_valid = self.hpricot_data.at(:IsValid).inner_html == "True"
  
  self.parse
  
  # is_valid only refers to the request, so we could still have errors - check and parse if present
  if !self.hpricot_data.at(:Errors).nil?
    self.hpricot_data.at(:Errors).search(:Error).each do |error|
      self.errors << Struct.new(:code, :message).new(error.at(:Code).inner_html, error.at(:Message).inner_html)
    end
  end
  
  # Return false if it's not a valid request, otherwise return the response
  self.is_valid ? self.response : false
end

#runObject

Launches the request’s query to Amazon (via query_amazon).



114
115
116
# File 'lib/amazon_product_advertising_api/operations/base.rb', line 114

def run
  self.query_amazon(params)
end