forked from rubyforgood/playtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
In preparation for rubyforgood#62, this commit pulls the endpoint-specific information out of the HTTPClient class and into and endpoint-specific class. Now HTTPClient is responsible only for managing the environment information and directing the user to the relevant endpoint. Adding a new endpoint is as simple as adding a method (ex. `item_search`) and corresponding class (ex. `ItemSearchEndpoint). The interface is *not* in its final form yet. This is just a good breaking point for a commit.
- Loading branch information
Showing
4 changed files
with
128 additions
and
104 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
require "amazon_product_api/search_response" | ||
|
||
module AmazonProductAPI | ||
# Responsible for building and executing an Amazon Product API search query. | ||
# | ||
# Any logic relating to searching, building the query string, authentication | ||
# signatures, etc. should live in this class. | ||
class ItemSearchEndpoint | ||
require "httparty" | ||
require "time" | ||
require "uri" | ||
require "openssl" | ||
require "base64" | ||
|
||
# The region you are interested in | ||
ENDPOINT = "webservices.amazon.com" | ||
REQUEST_URI = "/onca/xml" | ||
|
||
attr_accessor :query, :page, :aws_credentials | ||
|
||
def initialize(query, page, aws_credentials) | ||
@query = query | ||
@page = page | ||
@aws_credentials = aws_credentials | ||
end | ||
|
||
# Generate the signed URL | ||
def url | ||
raise InvalidQueryError unless query && page | ||
|
||
"http://#{ENDPOINT}#{REQUEST_URI}" + # base | ||
"?#{canonical_query_string}" + # query | ||
"&Signature=#{uri_escape(signature)}" # signature | ||
end | ||
|
||
# Send the HTTP request | ||
def get(http: HTTParty) | ||
http.get(url) | ||
end | ||
|
||
# Performs the search query and returns the resulting SearchResponse | ||
def response(http: HTTParty) | ||
response = get(http: http) | ||
SearchResponse.new parse_response(response) | ||
end | ||
|
||
|
||
private | ||
|
||
|
||
def parse_response(response) | ||
Hash.from_xml(response.body) | ||
end | ||
|
||
# Generate the signature required by the Product Advertising API | ||
def signature | ||
Base64.encode64(digest_with_key string_to_sign).strip | ||
end | ||
|
||
# Generate the string to be signed | ||
def string_to_sign | ||
"GET\n#{ENDPOINT}\n#{REQUEST_URI}\n#{canonical_query_string}" | ||
end | ||
|
||
# Generate the canonical query | ||
def canonical_query_string | ||
params.sort | ||
.map { |key, value| "#{uri_escape(key)}=#{uri_escape(value)}" } | ||
.join("&") | ||
end | ||
|
||
def params | ||
params = { | ||
"Service" => "AWSECommerceService", | ||
"Operation" => "ItemSearch", | ||
"AWSAccessKeyId" => aws_credentials.access_key, | ||
"AssociateTag" => aws_credentials.associate_tag, | ||
"SearchIndex" => "All", | ||
"Keywords" => query.to_s, | ||
"ResponseGroup" => "ItemAttributes,Offers,Images", | ||
"ItemPage" => page.to_s | ||
} | ||
|
||
# Set current timestamp if not set | ||
params["Timestamp"] ||= Time.now.gmtime.iso8601 | ||
params | ||
end | ||
|
||
def digest_with_key(string) | ||
OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha256"), | ||
aws_credentials.secret_key, | ||
string) | ||
end | ||
|
||
def uri_escape(phrase) | ||
URI.escape(phrase.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) | ||
end | ||
end | ||
end |
This file contains 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