Skip to content

Commit f8f60f1

Browse files
committed
Item lookup endpoint supports up to 10 ASINs
As a first step for batching the requests, this commit makes the client endpoint take a list of asins instead of just an individual one. Other files are changed in order to work with the new interface (asins -> items) Next up: bulk-searching with the items sync job!
1 parent fc74d99 commit f8f60f1

File tree

7 files changed

+122
-52
lines changed

7 files changed

+122
-52
lines changed

app/jobs/item_sync_job.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
class ItemSyncJob < ApplicationJob
1414
queue_as :default
1515

16+
def initialize
17+
@client = AmazonProductAPI::HTTPClient.new
18+
end
19+
1620
# Syncs all items and writes the results to the log
1721
def perform(*_args)
1822
Rails.logger.info bold_green('Syncing all items')
@@ -22,6 +26,8 @@ def perform(*_args)
2226

2327
private
2428

29+
attr_reader :client
30+
2531
def sync_all!
2632
# This is done in slices to avoid Amazon rate limits
2733
Item.all.each_slice(3) do |items|
@@ -41,8 +47,7 @@ def sync!(item)
4147
end
4248

4349
def amazon_item!(item)
44-
client = AmazonProductAPI::HTTPClient.new
45-
client.item_lookup(item.asin).response
50+
client.item_lookup(item.asin).response.first
4651
end
4752

4853
# Some styles for log text. This is so minor that it's not worth

lib/amazon_product_api/http_client.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ def item_search(query:, page: 1)
1919
ItemSearchEndpoint.new(query, page, aws_credentials)
2020
end
2121

22-
def item_lookup(asin)
23-
ItemLookupEndpoint.new(asin, aws_credentials)
22+
def item_lookup(*asin)
23+
ItemLookupEndpoint.new(*asin, aws_credentials)
2424
end
2525

2626
private

lib/amazon_product_api/item_lookup_endpoint.rb

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,27 @@ module AmazonProductAPI
1111
# Contains all specialization logic for this endpoint including request
1212
# parameters, parameter validation, and response parsing.
1313
class ItemLookupEndpoint < Endpoint
14-
def initialize(asin, aws_credentials)
15-
@asin = asin
14+
ASIN_LIMIT = 10 # max ASINs per request (from docs)
15+
16+
def initialize(*asins, aws_credentials)
17+
validate_asin_count(asins)
18+
19+
@asins = asins
1620
@aws_credentials = aws_credentials
1721
end
1822

1923
private
2024

21-
attr_reader :asin, :aws_credentials
25+
attr_reader :asins, :aws_credentials
26+
27+
def validate_asin_count(asins)
28+
return unless asins.count > ASIN_LIMIT
29+
raise ArgumentError,
30+
"Exceeded maximum ASIN limit: #{asins.length}/#{ASIN_LIMIT}"
31+
end
2232

2333
def process_response(response_hash)
24-
LookupResponse.new(response_hash).item
34+
LookupResponse.new(response_hash).items
2535
end
2636

2737
# Other request parameters for ItemLookup can be found here:
@@ -32,7 +42,8 @@ def request_params
3242
{
3343
'Operation' => 'ItemLookup',
3444
'ResponseGroup' => 'ItemAttributes,Offers,Images',
35-
'ItemId' => asin.to_s
45+
'IdType' => 'ASIN',
46+
'ItemId' => asins.join(',')
3647
}
3748
end
3849
end

lib/amazon_product_api/lookup_response.rb

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,34 @@ module AmazonProductAPI
1010
# file to touch if the API response changes.
1111
class LookupResponse
1212
def initialize(response_hash)
13-
@hash = item_hash_for response_hash
13+
@response_hash = response_hash
1414
end
1515

16-
def item(item_class: SearchItem)
17-
item_class.new(**item_attrs)
16+
def items(item_class: SearchItem)
17+
item_hashes.map { |hash| item_class.new(**item_attrs_from(hash)) }
1818
end
1919

2020
private
2121

22-
attr_reader :hash
22+
attr_reader :response_hash
2323

24-
def item_attrs
24+
def item_attrs_from(hash)
2525
{
2626
asin: hash['ASIN'],
2727

28-
price_cents: hash.dig('ItemAttributes', 'ListPrice', 'Amount').to_i,
28+
detail_page_url: hash['DetailPageURL'],
29+
title: hash['ItemAttributes']['Title'],
30+
price_cents: hash['ItemAttributes']['ListPrice']['Amount'].to_i,
2931

30-
image_url: hash.dig('SmallImage', 'URL') || '',
31-
image_width: hash.dig('SmallImage', 'Width') || '',
32-
image_height: hash.dig('SmallImage', 'Height') || '',
33-
34-
title: hash.dig('ItemAttributes', 'Title'),
35-
detail_page_url: hash['DetailPageURL']
32+
image_url: hash.dig('SmallImage', 'URL') || '',
33+
image_width: hash.dig('SmallImage', 'Width') || '',
34+
image_height: hash.dig('SmallImage', 'Height') || ''
3635
}
3736
end
3837

39-
def item_hash_for(response_hash)
40-
response_hash.dig('ItemLookupResponse', 'Items', 'Item') || []
38+
def item_hashes
39+
items = response_hash.dig('ItemLookupResponse', 'Items', 'Item') || []
40+
items.is_a?(Array) ? items : [items] # wrap "naked" response
4141
end
4242
end
4343
end

0 commit comments

Comments
 (0)