paapi 0.1.6 → 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 +7 -0
- data/README.md +0 -3
- data/lib/paapi/client.rb +57 -62
- data/lib/paapi/version.rb +1 -1
- data/lib/paapi.rb +57 -57
- data/paapi.gemspec +3 -2
- metadata +29 -8
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,3 +1,10 @@
|
|
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
|
6
|
+
- Add gem 'net-http-persistent' for connection persistance
|
7
|
+
- Remove the code which would use other http clients if available
|
1
8
|
## 0.1.3
|
2
9
|
- Dropped the HTTP gem and moved to Ruby's Net::HTTP
|
3
10
|
- Merged a branch which adds the Condtion parameter.
|
data/README.md
CHANGED
@@ -77,13 +77,10 @@ client = Paapi::Client.new(access_key: ENV['access_key'], secret_key: ENV['secre
|
|
77
77
|
gi = client.get_items(item_ids: '1857231384')
|
78
78
|
|
79
79
|
si = client.search_items(keywords: 'Harry Potter')
|
80
|
-
si = client.search_items(keywords: 'Harry Potter', SearchIndex)
|
81
80
|
|
82
81
|
gv = client.get_variations(asin: 'B00422MCUS')
|
83
82
|
```
|
84
83
|
|
85
|
-
You can access the response as a Hash, or
|
86
|
-
|
87
84
|
## Development
|
88
85
|
|
89
86
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/paapi/client.rb
CHANGED
@@ -1,95 +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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
else
|
33
|
-
@http = nil
|
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
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
35
|
def market=(a_market)
|
38
36
|
@market = a_market
|
39
37
|
@marketplace = MARKETPLACES[market.to_sym]
|
40
|
-
if
|
41
|
-
|
42
|
-
|
38
|
+
return if Paapi.partner_market.nil?
|
39
|
+
|
40
|
+
@partner_tag = Paapi.partner_market[a_market.to_sym] || @partner_tag
|
43
41
|
end
|
44
42
|
|
45
43
|
def get_items(item_ids:, **options)
|
46
|
-
payload = { ItemIds: Array(item_ids), Resources:
|
44
|
+
payload = {"PartnerTag" => partner_tag, "PartnerType" => "Associates", ItemIds: Array(item_ids), Resources: @resources}.merge(options)
|
47
45
|
request(op: :get_items, payload: payload)
|
48
46
|
end
|
49
47
|
|
50
|
-
def get_variations(asin:, **options
|
51
|
-
payload = {
|
48
|
+
def get_variations(asin:, **options)
|
49
|
+
payload = {ASIN: asin, Resources: @resources}.merge(options)
|
52
50
|
request(op: :get_variations, payload: payload)
|
53
51
|
end
|
54
52
|
|
55
53
|
# TODO: Currently we assume Keywords, but we need one of the following: [Keywords Actor Artist Author Brand Title ]
|
56
|
-
def search_items(
|
57
|
-
|
54
|
+
def search_items(**options)
|
55
|
+
options.transform_keys!(&:to_s)
|
56
|
+
raise ArgumentError.new("Missing keywords") unless (options.keys & SEARCH_PARAMS).length.positive?
|
58
57
|
|
59
|
-
search_index = options.dig(:SearchIndex) ||
|
58
|
+
search_index = options.dig(:SearchIndex) || "All"
|
60
59
|
|
61
|
-
payload = {
|
60
|
+
payload = {"PartnerTag" => partner_tag, "PartnerType" => "Associates", "Resources" => @resources, "ItemCount" => 10, "ItemPage" => 1, "SearchIndex" => search_index}.merge(options)
|
62
61
|
|
63
62
|
request(op: :search_items, payload: payload)
|
64
63
|
end
|
65
64
|
|
66
65
|
def get_browse_nodes(browse_node_ids:, **options)
|
67
|
-
payload = {
|
66
|
+
payload = {BrowseNodeIds: Array(browse_node_ids), Resources: @resources}.merge(options)
|
68
67
|
request(op: :get_browse_nodes, payload: payload)
|
69
68
|
end
|
70
|
-
|
69
|
+
|
71
70
|
private
|
72
|
-
|
73
|
-
def request(op:,
|
74
|
-
raise ArguemntError unless Paapi::OPERATIONS.
|
75
|
-
|
71
|
+
|
72
|
+
def request(op:, payload:)
|
73
|
+
raise ArguemntError unless Paapi::OPERATIONS.key?(op)
|
74
|
+
|
76
75
|
operation = OPERATIONS[op]
|
77
76
|
|
78
77
|
headers = {
|
79
|
-
|
80
|
-
|
78
|
+
"X-Amz-Target" => "com.amazon.paapi5.v1.ProductAdvertisingAPIv1.#{operation.target_name}",
|
79
|
+
"Content-Encoding" => "amz-1.0"
|
81
80
|
}
|
82
81
|
|
83
82
|
default_payload = {
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
83
|
+
"Condition" => condition,
|
84
|
+
"PartnerTag" => partner_tag,
|
85
|
+
"PartnerType" => partner_type,
|
86
|
+
"Marketplace" => marketplace.site
|
88
87
|
}
|
89
88
|
|
90
89
|
payload = default_payload.merge(payload)
|
91
|
-
|
92
|
-
endpoint =
|
90
|
+
puts payload
|
91
|
+
endpoint = "https://#{marketplace.host}/paapi5/#{operation.endpoint_suffix}"
|
93
92
|
|
94
93
|
signer = Aws::Sigv4::Signer.new(
|
95
94
|
service: operation.service,
|
@@ -102,29 +101,25 @@ module Paapi
|
|
102
101
|
|
103
102
|
signature = signer.sign_request(http_method: operation.http_method, url: endpoint, headers: headers, body: payload.to_json)
|
104
103
|
|
105
|
-
headers[
|
106
|
-
headers[
|
107
|
-
headers[
|
108
|
-
headers[
|
109
|
-
headers[
|
110
|
-
|
111
|
-
unless @http.nil?
|
112
|
-
Response.new( @http.with_headers(headers).post(endpoint, json: payload ) )
|
113
|
-
else
|
114
|
-
Response.new( Client.post(url: endpoint, body: payload, headers: headers))
|
115
|
-
end
|
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"
|
116
109
|
|
110
|
+
Response.new(post(url: endpoint, body: payload, headers: headers))
|
117
111
|
end
|
118
112
|
|
119
|
-
def
|
113
|
+
def post(url:, body:, headers:)
|
120
114
|
uri = URI.parse(url)
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
115
|
+
|
116
|
+
post_request = Net::HTTP::Post.new(uri.path)
|
117
|
+
post_request.content_type = "application/json; charset=UTF-8"
|
118
|
+
|
119
|
+
headers.each { |k, v| post_request[k] = v }
|
120
|
+
post_request.body = body.to_json
|
121
|
+
|
122
|
+
http.request uri, post_request
|
128
123
|
end
|
129
124
|
end
|
130
125
|
end
|
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
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
|
15
15
|
spec.metadata['homepage_uri'] = spec.homepage
|
16
16
|
spec.metadata['source_code_uri'] = spec.homepage
|
17
|
-
|
17
|
+
spec.metadata["changelog_uri"] = "https://github.com/dkam/paapi/blob/master/CHANGELOG.md"
|
18
18
|
|
19
19
|
# Specify which files should be added to the gem when it is released.
|
20
20
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
@@ -29,7 +29,8 @@ 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 '
|
32
|
+
spec.add_development_dependency 'standard'
|
33
33
|
|
34
34
|
spec.add_dependency 'aws-sigv4', '~> 1'
|
35
|
+
spec.add_dependency 'net-http-persistent', '~> 4.0', '>= 4.0.1'
|
35
36
|
end
|
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
|
@@ -67,19 +67,19 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '11'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: standard
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: aws-sigv4
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +94,26 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: net-http-persistent
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '4.0'
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 4.0.1
|
107
|
+
type: :runtime
|
108
|
+
prerelease: false
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - "~>"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '4.0'
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 4.0.1
|
97
117
|
description:
|
98
118
|
email:
|
99
119
|
- d@nmilne.com
|
@@ -123,6 +143,7 @@ licenses:
|
|
123
143
|
metadata:
|
124
144
|
homepage_uri: https://github.com/dkam/paapi
|
125
145
|
source_code_uri: https://github.com/dkam/paapi
|
146
|
+
changelog_uri: https://github.com/dkam/paapi/blob/master/CHANGELOG.md
|
126
147
|
post_install_message:
|
127
148
|
rdoc_options: []
|
128
149
|
require_paths:
|
@@ -138,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
159
|
- !ruby/object:Gem::Version
|
139
160
|
version: '0'
|
140
161
|
requirements: []
|
141
|
-
rubygems_version: 3.
|
162
|
+
rubygems_version: 3.5.17
|
142
163
|
signing_key:
|
143
164
|
specification_version: 4
|
144
165
|
summary: Client library for Amazon's Product Advertising API v5
|