paapi 0.1.8 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -1
- data/lib/paapi/client.rb +51 -46
- data/lib/paapi/version.rb +1 -1
- data/lib/paapi.rb +57 -57
- data/paapi.gemspec +1 -0
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11e336d12ee1e47e2a5e0721d03e36b8a0ef93c85cafa1f614cac918afc9562b
|
4
|
+
data.tar.gz: 45b7564fcdf20b532538adeb6dfe1187ffc084ee1cb3788da4c61cf36bc81d05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 793a70fd48443cc4a459aa2ec81507e7430810a1eb49a2446741dfb02135780bb7868c38a2adf87f1f4e4c99783669c55370eb6495a03657e332cf1d20ce812d
|
7
|
+
data.tar.gz: ca199ef19cadde87923b8bc8708ab8887bf91c0b61e63faf522b8ecdc91eea4ef25215a296ba9fe00dc6ccd9221c9dc8d20551fb87eea4c9d5cb282996cbbdf7
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
## 0.1.
|
1
|
+
## 0.1.9 (Unreleased)
|
2
|
+
- Fix bug allowing non-title case Request Parameters
|
3
|
+
- Add the required PartnerTag and PartnerType key values to the search body request
|
4
|
+
|
5
|
+
## 0.1.7
|
2
6
|
- Add gem 'net-http-persistent' for connection persistance
|
3
7
|
- Remove the code which would use other http clients if available
|
4
8
|
## 0.1.3
|
data/lib/paapi/client.rb
CHANGED
@@ -1,89 +1,94 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "net/http/persistent"
|
2
|
+
require "aws-sigv4"
|
3
3
|
|
4
4
|
module Paapi
|
5
5
|
class Client
|
6
|
-
|
7
6
|
attr_accessor :partner_tag, :marketplace, :resources, :condition
|
8
7
|
attr_reader :partner_type, :access_key, :secret_key, :market, :http
|
9
8
|
|
10
|
-
def initialize(
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
9
|
+
def initialize(
|
10
|
+
access_key: Paapi.access_key,
|
11
|
+
secret_key: Paapi.secret_key,
|
12
|
+
partner_tag: Paapi.partner_tag,
|
13
|
+
market: Paapi.market || DEFAULT_MARKET,
|
14
|
+
condition: Paapi.condition || DEFAULT_CONDITION,
|
15
|
+
resources: Paapi.resources || DEFAULT_RESOURCES,
|
16
|
+
partner_type: DEFAULT_PARTNER_TYPE
|
17
|
+
)
|
18
|
+
raise ArgumentError unless MARKETPLACES.key?(market.to_sym)
|
19
19
|
|
20
20
|
@access_key = access_key
|
21
21
|
@secret_key = secret_key
|
22
22
|
@partner_type = partner_type
|
23
23
|
@resources = resources unless resources.nil?
|
24
|
-
@condition = condition
|
24
|
+
@condition = condition
|
25
25
|
self.market = market
|
26
26
|
@partner_tag = partner_tag if !partner_tag.nil?
|
27
27
|
|
28
|
-
@http = Net::HTTP::Persistent.new
|
28
|
+
@http = Net::HTTP::Persistent.new(name: "paapi").tap do |c|
|
29
|
+
c.open_timeout = 2
|
30
|
+
c.read_timeout = 5
|
31
|
+
c.write_timeout = 5
|
32
|
+
end
|
29
33
|
end
|
30
34
|
|
31
35
|
def market=(a_market)
|
32
36
|
@market = a_market
|
33
37
|
@marketplace = MARKETPLACES[market.to_sym]
|
34
|
-
if
|
35
|
-
|
36
|
-
|
38
|
+
return if Paapi.partner_market.nil?
|
39
|
+
|
40
|
+
@partner_tag = Paapi.partner_market[a_market.to_sym] || @partner_tag
|
37
41
|
end
|
38
42
|
|
39
43
|
def get_items(item_ids:, **options)
|
40
|
-
payload = { ItemIds: Array(item_ids), Resources:
|
44
|
+
payload = {"PartnerTag" => partner_tag, "PartnerType" => "Associates", ItemIds: Array(item_ids), Resources: @resources}.merge(options)
|
41
45
|
request(op: :get_items, payload: payload)
|
42
46
|
end
|
43
47
|
|
44
|
-
def get_variations(asin:, **options
|
45
|
-
payload = {
|
48
|
+
def get_variations(asin:, **options)
|
49
|
+
payload = {ASIN: asin, Resources: @resources}.merge(options)
|
46
50
|
request(op: :get_variations, payload: payload)
|
47
51
|
end
|
48
52
|
|
49
53
|
# TODO: Currently we assume Keywords, but we need one of the following: [Keywords Actor Artist Author Brand Title ]
|
50
|
-
def search_items(
|
51
|
-
|
54
|
+
def search_items(**options)
|
55
|
+
options.transform_keys!(&:to_s)
|
56
|
+
raise ArgumentError.new("Missing keywords") unless (options.keys & SEARCH_PARAMS).length.positive?
|
52
57
|
|
53
|
-
search_index = options.dig(:SearchIndex) ||
|
58
|
+
search_index = options.dig(:SearchIndex) || "All"
|
54
59
|
|
55
|
-
payload = {
|
60
|
+
payload = {"PartnerTag" => partner_tag, "PartnerType" => "Associates", "Resources" => @resources, "ItemCount" => 10, "ItemPage" => 1, "SearchIndex" => search_index}.merge(options)
|
56
61
|
|
57
62
|
request(op: :search_items, payload: payload)
|
58
63
|
end
|
59
64
|
|
60
65
|
def get_browse_nodes(browse_node_ids:, **options)
|
61
|
-
payload = {
|
66
|
+
payload = {BrowseNodeIds: Array(browse_node_ids), Resources: @resources}.merge(options)
|
62
67
|
request(op: :get_browse_nodes, payload: payload)
|
63
68
|
end
|
64
|
-
|
69
|
+
|
65
70
|
private
|
66
|
-
|
67
|
-
def request(op:,
|
68
|
-
raise ArguemntError unless Paapi::OPERATIONS.
|
69
|
-
|
71
|
+
|
72
|
+
def request(op:, payload:)
|
73
|
+
raise ArguemntError unless Paapi::OPERATIONS.key?(op)
|
74
|
+
|
70
75
|
operation = OPERATIONS[op]
|
71
76
|
|
72
77
|
headers = {
|
73
|
-
|
74
|
-
|
78
|
+
"X-Amz-Target" => "com.amazon.paapi5.v1.ProductAdvertisingAPIv1.#{operation.target_name}",
|
79
|
+
"Content-Encoding" => "amz-1.0"
|
75
80
|
}
|
76
81
|
|
77
82
|
default_payload = {
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
83
|
+
"Condition" => condition,
|
84
|
+
"PartnerTag" => partner_tag,
|
85
|
+
"PartnerType" => partner_type,
|
86
|
+
"Marketplace" => marketplace.site
|
82
87
|
}
|
83
88
|
|
84
89
|
payload = default_payload.merge(payload)
|
85
|
-
|
86
|
-
endpoint =
|
90
|
+
puts payload
|
91
|
+
endpoint = "https://#{marketplace.host}/paapi5/#{operation.endpoint_suffix}"
|
87
92
|
|
88
93
|
signer = Aws::Sigv4::Signer.new(
|
89
94
|
service: operation.service,
|
@@ -96,21 +101,21 @@ module Paapi
|
|
96
101
|
|
97
102
|
signature = signer.sign_request(http_method: operation.http_method, url: endpoint, headers: headers, body: payload.to_json)
|
98
103
|
|
99
|
-
headers[
|
100
|
-
headers[
|
101
|
-
headers[
|
102
|
-
headers[
|
103
|
-
headers[
|
104
|
+
headers["Host"] = marketplace.host
|
105
|
+
headers["X-Amz-Date"] = signature.headers["x-amz-date"]
|
106
|
+
headers["X-Amz-Content-Sha256"] = signature.headers["x-amz-content-sha256"]
|
107
|
+
headers["Authorization"] = signature.headers["authorization"]
|
108
|
+
headers["Content-Type"] = "application/json; charset=utf-8"
|
104
109
|
|
105
|
-
Response.new(
|
110
|
+
Response.new(post(url: endpoint, body: payload, headers: headers))
|
106
111
|
end
|
107
112
|
|
108
113
|
def post(url:, body:, headers:)
|
109
114
|
uri = URI.parse(url)
|
110
115
|
|
111
116
|
post_request = Net::HTTP::Post.new(uri.path)
|
112
|
-
post_request.content_type =
|
113
|
-
|
117
|
+
post_request.content_type = "application/json; charset=UTF-8"
|
118
|
+
|
114
119
|
headers.each { |k, v| post_request[k] = v }
|
115
120
|
post_request.body = body.to_json
|
116
121
|
|
data/lib/paapi/version.rb
CHANGED
data/lib/paapi.rb
CHANGED
@@ -1,81 +1,82 @@
|
|
1
|
-
require
|
1
|
+
require "paapi/version"
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require "paapi/client"
|
4
|
+
require "paapi/item"
|
5
|
+
require "paapi/listing"
|
6
|
+
require "paapi/response"
|
7
7
|
|
8
8
|
module Paapi
|
9
9
|
class Error < StandardError; end
|
10
|
+
|
10
11
|
class NotImplemented < StandardError; end
|
11
|
-
SEARCH_PARAMS = %
|
12
|
-
DEFAULT_PARTNER_TYPE =
|
12
|
+
SEARCH_PARAMS = %w[Keywords Actor Artist Author Brand Title].freeze
|
13
|
+
DEFAULT_PARTNER_TYPE = "Associates"
|
13
14
|
DEFAULT_MARKET = :us
|
14
|
-
DEFAULT_CONDITION
|
15
|
+
DEFAULT_CONDITION = "Any"
|
15
16
|
DEFAULT_RESOURCES = [
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
17
|
+
"Images.Primary.Large",
|
18
|
+
"ItemInfo.ByLineInfo",
|
19
|
+
"ItemInfo.ContentInfo",
|
20
|
+
"ItemInfo.ExternalIds",
|
21
|
+
"ItemInfo.Features",
|
22
|
+
"ItemInfo.ManufactureInfo",
|
23
|
+
"ItemInfo.ProductInfo",
|
24
|
+
"ItemInfo.TechnicalInfo", # Includes format when Kindle
|
25
|
+
"ItemInfo.Title",
|
26
|
+
"ItemInfo.TradeInInfo",
|
27
|
+
"Offers.Listings.Availability.Message",
|
28
|
+
"Offers.Listings.Condition",
|
29
|
+
"Offers.Listings.Condition.SubCondition",
|
30
|
+
"Offers.Listings.DeliveryInfo.IsAmazonFulfilled",
|
31
|
+
"Offers.Listings.DeliveryInfo.IsFreeShippingEligible",
|
32
|
+
"Offers.Listings.DeliveryInfo.IsPrimeEligible",
|
33
|
+
"Offers.Listings.MerchantInfo",
|
34
|
+
"Offers.Listings.Price",
|
35
|
+
"Offers.Listings.SavingBasis"
|
35
36
|
].freeze
|
36
37
|
|
37
38
|
Locale = Struct.new(:key, :name, :host, :region) do
|
38
39
|
def site
|
39
|
-
host.sub(
|
40
|
+
host.sub("webservices", "www")
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
44
|
MARKETPLACES = {
|
44
|
-
au: Locale.new(:au,
|
45
|
-
br: Locale.new(:br,
|
46
|
-
ca: Locale.new(:ca,
|
47
|
-
fr: Locale.new(:fr,
|
48
|
-
de: Locale.new(:de,
|
49
|
-
in: Locale.new(:in,
|
50
|
-
it: Locale.new(:it,
|
51
|
-
jp: Locale.new(:jp,
|
52
|
-
mx: Locale.new(:mx,
|
53
|
-
es: Locale.new(:es,
|
54
|
-
tr: Locale.new(:tk,
|
55
|
-
ae: Locale.new(:ae,
|
56
|
-
uk: Locale.new(:uk,
|
57
|
-
us: Locale.new(:us,
|
45
|
+
au: Locale.new(:au, "Australia", "webservices.amazon.com.au", "us-west-2"),
|
46
|
+
br: Locale.new(:br, "Brazil", "webservices.amazon.com.br", "us-east-1"),
|
47
|
+
ca: Locale.new(:ca, "Canada", "webservices.amazon.ca", "us-east-1"),
|
48
|
+
fr: Locale.new(:fr, "France", "webservices.amazon.fr", "eu-west-1"),
|
49
|
+
de: Locale.new(:de, "Germany", "webservices.amazon.de", "eu-west-1"),
|
50
|
+
in: Locale.new(:in, "India", "webservices.amazon.in", "eu-west-1"),
|
51
|
+
it: Locale.new(:it, "Italy", "webservices.amazon.it", "eu-west-1"),
|
52
|
+
jp: Locale.new(:jp, "Japan", "webservices.amazon.co.jp", "us-west-2"),
|
53
|
+
mx: Locale.new(:mx, "Mexico", "webservices.amazon.com.mx", "us-east-1"),
|
54
|
+
es: Locale.new(:es, "Spain", "webservices.amazon.es", "eu-west-1"),
|
55
|
+
tr: Locale.new(:tk, "Turkey", "webservices.amazon.com.tr", "eu-west-1"),
|
56
|
+
ae: Locale.new(:ae, "United Arab Emirates", "webservices.amazon.ae", "eu-west-1"),
|
57
|
+
uk: Locale.new(:uk, "United Kingdom", "webservices.amazon.co.uk", "eu-west-1"),
|
58
|
+
us: Locale.new(:us, "United States", "webservices.amazon.com", "us-east-1")
|
58
59
|
}.freeze
|
59
60
|
|
60
|
-
Operation = Struct.new(:target_name, :endpoint_suffix, :http_method, :service
|
61
|
+
Operation = Struct.new(:target_name, :endpoint_suffix, :http_method, :service)
|
61
62
|
|
62
63
|
OPERATIONS = {
|
63
|
-
get_browse_nodes: Operation.new(
|
64
|
-
get_items:
|
65
|
-
get_variations:
|
66
|
-
search_items:
|
64
|
+
get_browse_nodes: Operation.new("GetBrowseNodes", "getbrowsenodes", "POST", "ProductAdvertisingAPI"),
|
65
|
+
get_items: Operation.new("GetItems", "getitems", "POST", "ProductAdvertisingAPI"),
|
66
|
+
get_variations: Operation.new("GetVariations", "getvariations", "POST", "ProductAdvertisingAPI"),
|
67
|
+
search_items: Operation.new("SearchItems", "searchitems", "POST", "ProductAdvertisingAPI")
|
67
68
|
}.freeze
|
68
69
|
|
69
70
|
class << self
|
70
71
|
attr_accessor :access_key,
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
72
|
+
:secret_key,
|
73
|
+
:partner_tag,
|
74
|
+
:partner_type,
|
75
|
+
:market,
|
76
|
+
:partner_market,
|
77
|
+
:condition,
|
78
|
+
:resources,
|
79
|
+
:test_mode
|
79
80
|
|
80
81
|
def configure
|
81
82
|
yield self
|
@@ -85,7 +86,6 @@ module Paapi
|
|
85
86
|
end
|
86
87
|
|
87
88
|
def symbolize_keys(hash)
|
88
|
-
|
89
|
+
hash.map { |k, v| v.is_a?(Hash) ? [k.to_sym, symbolize_keys(v)] : [k.to_sym, v] }.to_h
|
89
90
|
end
|
90
91
|
end
|
91
|
-
|
data/paapi.gemspec
CHANGED
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_development_dependency 'rake', '>= 12.3.r3'
|
30
30
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
31
31
|
spec.add_development_dependency 'byebug', '~> 11'
|
32
|
+
spec.add_development_dependency 'standard'
|
32
33
|
|
33
34
|
spec.add_dependency 'aws-sigv4', '~> 1'
|
34
35
|
spec.add_dependency 'net-http-persistent', '~> 4.0', '>= 4.0.1'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Milne
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '11'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: standard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: aws-sigv4
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
159
|
- !ruby/object:Gem::Version
|
146
160
|
version: '0'
|
147
161
|
requirements: []
|
148
|
-
rubygems_version: 3.
|
162
|
+
rubygems_version: 3.5.17
|
149
163
|
signing_key:
|
150
164
|
specification_version: 4
|
151
165
|
summary: Client library for Amazon's Product Advertising API v5
|