Created
February 18, 2015 21:08
-
-
Save jonahb/09c573c37ddcfcb8406d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'uri' | |
require 'base64' | |
require 'openssl' | |
require 'time' | |
require 'net/http' | |
require 'base64' | |
require 'nokogiri' | |
module AmazonProductAdvertising | |
class Error < StandardError | |
attr_reader :code | |
def initialize(message, code) | |
super(message) | |
@code = code | |
end | |
end | |
class Client | |
APIVersion = '2011-08-01' | |
EndpointPath = '/onca/xml' | |
LocaleToHost = { | |
'US' => 'webservices.amazon.com' | |
} | |
PrefixToNamespace = { | |
'a' => 'http://webservices.amazon.com/AWSECommerceService/2011-08-01', | |
'e' => 'http://ecs.amazonaws.com/doc/2011-08-01/' | |
} | |
attr_reader :aws_access_key_id | |
attr_reader :aws_secret_access_key | |
attr_reader :associate_tag | |
attr_reader :locale | |
attr_reader :secure | |
def initialize(aws_access_key_id, aws_secret_access_key, associate_tag, locale: 'US', secure: false) | |
@aws_access_key_id = aws_access_key_id | |
@aws_secret_access_key = aws_secret_access_key | |
@associate_tag = associate_tag | |
@secure = secure | |
unless LocaleToHost.key?(locale) | |
raise ArgumentError, "Invalid locale: '#{locale}'" | |
end | |
@locale = locale | |
end | |
def item_search(search_index, params = {}) | |
invoke 'ItemSearch', params.merge('SearchIndex' => search_index) | |
end | |
def item_lookup(item_id, params = {}) | |
invoke 'ItemLookup', params.merge('ItemId' => item_id) | |
end | |
private | |
def invoke(operation, params = {}) | |
params = params.merge( | |
'AssociateTag' => associate_tag, | |
'AWSAccessKeyId' => aws_access_key_id, | |
'Operation' => operation, | |
'Service' => 'AWSECommerceService', | |
'Timestamp' => Time.now.utc.iso8601, | |
'Version' => APIVersion) | |
scheme = secure ? 'https' : 'http' | |
query = sign(params) | |
uri = URI("#{scheme}://#{host}#{EndpointPath}?#{query}") | |
handle_response Net::HTTP.get_response(uri) | |
end | |
def handle_response(response) | |
doc = Nokogiri::XML(response.body) | |
error = doc.at_xpath('//a:Error | //e:Error', PrefixToNamespace) | |
if error | |
message = error % 'Message' | |
code = error % 'Code' | |
raise Error.new(message && message.text, code && code.text) | |
end | |
doc | |
end | |
def sign(params) | |
sorted_params = params.sort { |(k1, _), (k2, _)| k1.bytes <=> k2.bytes } | |
query = uri_encode_params(sorted_params) | |
message = ['GET', host, EndpointPath, query].join("\n") | |
digest = OpenSSL::Digest::SHA256.new | |
signature = OpenSSL::HMAC.digest(digest, aws_secret_access_key, message) | |
param = uri_encode(Base64.encode64(signature).chomp) | |
query + "&Signature=#{param}" | |
end | |
def host | |
LocaleToHost[locale] | |
end | |
def uri_encode_params(params) | |
params.collect do |k, v| | |
"#{uri_encode(k)}=#{uri_encode(v)}" | |
end.join('&') | |
end | |
def uri_encode(string) | |
URI.encode_www_form_component(string).gsub('+', '%20') | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment