paapi 0.0.3 → 0.0.4
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/README.md +6 -2
- data/bin/console +1 -0
- data/lib/paapi/client.rb +52 -21
- data/lib/paapi/item.rb +32 -24
- data/lib/paapi/response.rb +10 -26
- data/lib/paapi/version.rb +1 -1
- data/lib/paapi.rb +0 -1
- metadata +2 -3
- data/lib/paapi/aws_request.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c51a902c63c17b386688df97e49c8b201fb3309de82ace4b9e9b5d9f420923ff
|
4
|
+
data.tar.gz: c312da6d5bfb22c21b43f5449e616c48fcf661dfd08e9e4b2e106512c6c5575d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f76777564d20118875ecb809a5c32c88a7d58245b3012947a4a55ac150e182e88cf34179de9e60999dd03b404cd9dea136346e12aec7199161ab122bf62f6f00
|
7
|
+
data.tar.gz: b2c64410108d2d2e4ce5e8bed0a1da8eee6d4fff83fd3c176b737e771d030cb5972c6e9cf84a3b26de2673f6b15116a622b7d3423b1bde252fbfd66c97e1dcdc
|
data/README.md
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
`paapi` is a slim wrapper around [Amazon's Product Advertising API 5.0](https://webservices.amazon.com/paapi5/documentation/).
|
4
4
|
|
5
|
-
This gem is under development and currently incomplete.
|
5
|
+
This gem is under heavy development and currently incomplete.
|
6
|
+
|
7
|
+
[](https://travis-ci.org/dkam/paapi)
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
@@ -24,7 +26,7 @@ Or install it yourself as:
|
|
24
26
|
|
25
27
|
### Configuration
|
26
28
|
|
27
|
-
The library can be
|
29
|
+
The library can be configured with an initializer. For Rails, create the file `config/initializers/paapi.rb`
|
28
30
|
|
29
31
|
```ruby
|
30
32
|
Paapi.configure do |config|
|
@@ -83,6 +85,8 @@ gv = client.get_variations(asin: 'B00422MCUS')
|
|
83
85
|
|
84
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.
|
85
87
|
|
88
|
+
If you create a file `config.rb`, it will be loaded by `bin/console`, allowing you to configure keys and markets.
|
89
|
+
|
86
90
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
87
91
|
|
88
92
|
## Contributing
|
data/bin/console
CHANGED
data/lib/paapi/client.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'http'
|
2
|
+
require 'aws-sigv4'
|
2
3
|
|
3
4
|
module Paapi
|
4
5
|
class Client
|
5
|
-
|
6
|
+
|
6
7
|
attr_accessor :partner_tag, :marketplace, :resources
|
7
8
|
attr_reader :partner_type, :access_key, :secret_key, :market
|
8
9
|
|
@@ -14,13 +15,14 @@ module Paapi
|
|
14
15
|
partner_type: DEFAULT_PARTNER_TYPE
|
15
16
|
)
|
16
17
|
raise ArgumentError unless MARKETPLACES.keys.include?(market.to_sym)
|
18
|
+
|
17
19
|
@access_key = access_key
|
18
20
|
@secret_key = secret_key
|
19
21
|
@partner_type = partner_type
|
20
22
|
@resources = resources unless resources.nil?
|
21
23
|
|
22
24
|
self.market = market
|
23
|
-
@partner_tag = partner_tag if !partner_tag.nil?
|
25
|
+
@partner_tag = partner_tag if !partner_tag.nil?
|
24
26
|
end
|
25
27
|
|
26
28
|
def market=(a_market)
|
@@ -33,23 +35,14 @@ module Paapi
|
|
33
35
|
|
34
36
|
def get_items(item_ids:, **options)
|
35
37
|
payload = { ItemIds: Array(item_ids), Resources: @resources }
|
36
|
-
|
37
|
-
res = do_request(op: :get_items, payload: payload)
|
38
|
-
|
39
|
-
# Errors, ItemResults -> Items -> Item
|
40
|
-
return Response.new(res)
|
38
|
+
request(op: :get_items, payload: payload)
|
41
39
|
end
|
42
40
|
|
43
41
|
def get_variations(asin:, **options )
|
44
42
|
payload = { ASIN: asin, Resources: @resources }
|
45
|
-
|
46
|
-
res = do_request(op: :get_variations, payload: payload)
|
47
|
-
|
48
|
-
# Errors, VariationsResult->Items
|
49
|
-
Response.new(res)
|
43
|
+
request(op: :get_variations, payload: payload)
|
50
44
|
end
|
51
45
|
|
52
|
-
|
53
46
|
# TODO: Currently we assume Keywords, but we need one of the follow: [Keywords Actor Artist Author Brand Title ]
|
54
47
|
def search_items(keywords: nil, **options )
|
55
48
|
raise ArgumentError("Missing keywords") unless (options.keys | SEARCH_PARAMS).length.positive?
|
@@ -58,18 +51,56 @@ module Paapi
|
|
58
51
|
|
59
52
|
payload = { Keywords: keywords, Resources: @resources, ItemCount: 10, ItemPage: 1, SearchIndex: search_index }.merge(options)
|
60
53
|
|
61
|
-
|
62
|
-
|
63
|
-
Response.new(res)
|
54
|
+
request(op: :search_items, payload: payload)
|
64
55
|
end
|
65
56
|
|
66
57
|
def get_browse_nodes(browse_node_ids:, **options)
|
67
|
-
resources = ['BrowseNodes.Ancestor', 'BrowseNodes.Children']
|
68
58
|
payload = { BrowseNodeIds: Array(browse_node_ids), Resources: @resources }.merge(options)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
59
|
+
request(op: :get_browse_nodes, payload: payload)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def request(op:, payload:)
|
65
|
+
raise ArguemntError unless Paapi::OPERATIONS.keys.include?(op)
|
66
|
+
|
67
|
+
operation = OPERATIONS[op]
|
68
|
+
|
69
|
+
headers = {
|
70
|
+
'X-Amz-Target' => "com.amazon.paapi5.v1.ProductAdvertisingAPIv1.#{operation.target_name}",
|
71
|
+
'Content-Encoding' => 'amz-1.0',
|
72
|
+
}
|
73
|
+
|
74
|
+
default_payload = {
|
75
|
+
'PartnerTag' => partner_tag,
|
76
|
+
'PartnerType' => partner_type,
|
77
|
+
'Marketplace' => marketplace.site
|
78
|
+
}
|
79
|
+
|
80
|
+
payload = default_payload.merge(payload)
|
81
|
+
|
82
|
+
endpoint = "https://#{marketplace.host}/paapi5/#{operation.endpoint_suffix}"
|
83
|
+
|
84
|
+
signer = Aws::Sigv4::Signer.new(
|
85
|
+
service: operation.service,
|
86
|
+
region: marketplace.region,
|
87
|
+
access_key_id: access_key,
|
88
|
+
secret_access_key: secret_key,
|
89
|
+
http_method: operation.http_method,
|
90
|
+
endpoint: marketplace.host
|
91
|
+
)
|
92
|
+
|
93
|
+
signature = signer.sign_request(http_method: operation.http_method, url: endpoint, headers: headers, body: payload.to_json)
|
94
|
+
|
95
|
+
headers['Host'] = marketplace.host
|
96
|
+
headers['X-Amz-Date'] = signature.headers['x-amz-date']
|
97
|
+
headers['X-Amz-Content-Sha256']= signature.headers['x-amz-content-sha256']
|
98
|
+
headers['Authorization'] = signature.headers['authorization']
|
99
|
+
headers['Content-Type'] = 'application/json; charset=utf-8'
|
100
|
+
|
101
|
+
Response.new( HTTP.headers(headers).post(endpoint, json: payload ) )
|
73
102
|
end
|
74
103
|
end
|
104
|
+
|
105
|
+
|
75
106
|
end
|
data/lib/paapi/item.rb
CHANGED
@@ -2,9 +2,13 @@ require 'nameable'
|
|
2
2
|
|
3
3
|
module Paapi
|
4
4
|
class Item
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :hash
|
6
6
|
def initialize(data)
|
7
|
-
@
|
7
|
+
@hash = data
|
8
|
+
end
|
9
|
+
|
10
|
+
def listings
|
11
|
+
get(['Offers', 'Listings']).map {|d| Listing.new(d)}
|
8
12
|
end
|
9
13
|
|
10
14
|
def asin
|
@@ -22,20 +26,20 @@ module Paapi
|
|
22
26
|
def title
|
23
27
|
get(%w{ItemInfo Title DisplayValue})
|
24
28
|
end
|
25
|
-
|
29
|
+
|
26
30
|
def manufacturer
|
27
31
|
get(%w{ItemInfo ByLineInfo Manufacturer DisplayValue})
|
28
32
|
end
|
29
|
-
|
33
|
+
|
30
34
|
def publisher
|
31
35
|
manufacturer
|
32
36
|
end
|
33
|
-
|
37
|
+
|
34
38
|
def publication_date
|
35
39
|
d = get(%w{ItemInfo ContentInfo PublicationDate DisplayValue})
|
36
40
|
return d.nil? ? nil : Date.parse(d)
|
37
41
|
end
|
38
|
-
|
42
|
+
|
39
43
|
def release_date
|
40
44
|
d = get(%w{ItemInfo ProductInfo ReleaseDate DisplayValue})
|
41
45
|
return d.nil? ? nil : Date.parse(d)
|
@@ -44,33 +48,33 @@ module Paapi
|
|
44
48
|
def contributors
|
45
49
|
get(%w{ItemInfo ByLineInfo Contributors})
|
46
50
|
end
|
47
|
-
|
51
|
+
|
48
52
|
def contributors_of(kind)
|
49
|
-
contributors&.select { |e| e['Role'] == kind }&.map { |e| Nameable(e['Name'])}
|
53
|
+
contributors&.select { |e| e['Role'] == kind.to_s.gsub(/([[:alpha:]]+)/) { |w| w.capitalize } }&.map { |e| Nameable(e['Name'])}
|
50
54
|
end
|
51
|
-
|
55
|
+
|
56
|
+
def actors
|
57
|
+
contributors_of 'Actor'
|
58
|
+
end
|
59
|
+
|
60
|
+
def artists
|
61
|
+
contributors_of 'Artist'
|
62
|
+
end
|
63
|
+
|
52
64
|
def authors
|
53
65
|
contributors_of 'Author'
|
54
66
|
end
|
55
|
-
|
67
|
+
|
56
68
|
def illustrators
|
57
69
|
contributors_of 'Illustrator'
|
58
70
|
end
|
59
|
-
|
60
|
-
def actors
|
61
|
-
contributors_of 'Actor'
|
62
|
-
end
|
63
71
|
|
64
72
|
def narrators
|
65
73
|
contributors_of 'Narrator'
|
66
74
|
end
|
67
|
-
|
68
|
-
def publishers
|
69
|
-
contributors_of 'Publisher'
|
70
|
-
end
|
71
75
|
|
72
|
-
def
|
73
|
-
|
76
|
+
def publishers
|
77
|
+
contributors_of 'Publisher'
|
74
78
|
end
|
75
79
|
|
76
80
|
def eans
|
@@ -84,7 +88,7 @@ module Paapi
|
|
84
88
|
def features
|
85
89
|
get(%w{ItemInfo Features DisplayValues})&.join(' ')
|
86
90
|
end
|
87
|
-
|
91
|
+
|
88
92
|
def brand
|
89
93
|
get(%w{ItemInfo ByLineInfo Brand DisplayValue})
|
90
94
|
end
|
@@ -93,6 +97,10 @@ module Paapi
|
|
93
97
|
get(%w{ItemInfo ManufactureInfo ItemPartNumber DisplayValue})
|
94
98
|
end
|
95
99
|
|
100
|
+
def model
|
101
|
+
get(%w{ItemInfo ManufactureInfo Model})
|
102
|
+
end
|
103
|
+
|
96
104
|
def package
|
97
105
|
get(%w{ItemInfo TechnicalInfo Formats DisplayValues})
|
98
106
|
end
|
@@ -102,12 +110,12 @@ module Paapi
|
|
102
110
|
end
|
103
111
|
|
104
112
|
def get(keys)
|
105
|
-
@
|
113
|
+
@hash.dig(*keys)
|
106
114
|
end
|
107
|
-
|
115
|
+
|
108
116
|
def self.to_items(data)
|
109
117
|
data.map {|d| Item.new(d)}
|
110
118
|
end
|
111
|
-
|
119
|
+
|
112
120
|
end
|
113
121
|
end
|
data/lib/paapi/response.rb
CHANGED
@@ -2,41 +2,25 @@ require 'json'
|
|
2
2
|
|
3
3
|
module Paapi
|
4
4
|
class Response
|
5
|
-
attr_reader :http_response, :
|
5
|
+
attr_reader :http_response, :json, :datas, :doc, :items
|
6
6
|
|
7
7
|
def initialize(response)
|
8
8
|
@http_response = response
|
9
|
-
@
|
10
|
-
|
11
|
-
@datas = symbolise(JSON.parse(response.body.to_s))
|
12
|
-
@doc = JSON.parse(@datas.to_json, object_class: OpenStruct)
|
9
|
+
@json = JSON.parse(response.body.to_s)
|
13
10
|
|
14
|
-
@items_data = @
|
15
|
-
@items_data ||= @
|
11
|
+
@items_data = @json.dig('ItemsResult', 'Items')
|
12
|
+
@items_data ||= @json.dig('SearchResult', 'Items')
|
16
13
|
@items_data ||= []
|
17
|
-
|
14
|
+
|
18
15
|
@items = @items_data.map {|d| Item.new(d)}
|
19
16
|
|
20
17
|
end
|
21
|
-
|
22
|
-
def
|
23
|
-
|
24
|
-
s.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
|
25
|
-
gsub(/([a-z])([A-Z])/, '\1_\2').
|
26
|
-
downcase
|
27
|
-
end
|
28
|
-
|
29
|
-
def symbolise(obj)
|
30
|
-
if obj.is_a? Hash
|
31
|
-
return obj.inject({}) do |memo, (k, v)|
|
32
|
-
memo.tap { |m| m[snake_case(k)] = symbolise(v) }
|
33
|
-
end
|
34
|
-
elsif obj.is_a? Array
|
35
|
-
return obj.map { |memo| symbolise(memo) }
|
36
|
-
end
|
37
|
-
obj
|
18
|
+
|
19
|
+
def result_count
|
20
|
+
@json.dig('SearchResult', 'TotalResultCount')
|
38
21
|
end
|
39
22
|
|
40
|
-
|
23
|
+
|
24
|
+
|
41
25
|
end
|
42
26
|
end
|
data/lib/paapi/version.rb
CHANGED
data/lib/paapi.rb
CHANGED
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.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Milne
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -138,7 +138,6 @@ files:
|
|
138
138
|
- bin/console
|
139
139
|
- bin/setup
|
140
140
|
- lib/paapi.rb
|
141
|
-
- lib/paapi/aws_request.rb
|
142
141
|
- lib/paapi/client.rb
|
143
142
|
- lib/paapi/item.rb
|
144
143
|
- lib/paapi/response.rb
|
data/lib/paapi/aws_request.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'http'
|
2
|
-
require 'aws-sigv4'
|
3
|
-
|
4
|
-
# https://webservices.amazon.com/paapi5/documentation/common-request-parameters.html
|
5
|
-
module Paapi
|
6
|
-
module AwsRequest
|
7
|
-
def do_request(op:, payload:)
|
8
|
-
raise ArguemntError unless Paapi::OPERATIONS.keys.include?(op)
|
9
|
-
|
10
|
-
operation = OPERATIONS[op]
|
11
|
-
|
12
|
-
headers = {
|
13
|
-
'X-Amz-Target' => "com.amazon.paapi5.v1.ProductAdvertisingAPIv1.#{operation.target_name}",
|
14
|
-
'Content-Encoding' => 'amz-1.0',
|
15
|
-
}
|
16
|
-
|
17
|
-
default_payload = {
|
18
|
-
'PartnerTag' => partner_tag,
|
19
|
-
'PartnerType' => partner_type,
|
20
|
-
'Marketplace' => marketplace.site
|
21
|
-
}
|
22
|
-
|
23
|
-
payload = default_payload.merge(payload)
|
24
|
-
|
25
|
-
endpoint = "https://#{marketplace.host}/paapi5/#{operation.endpoint_suffix}"
|
26
|
-
|
27
|
-
signer = Aws::Sigv4::Signer.new(
|
28
|
-
service: operation.service,
|
29
|
-
region: marketplace.region,
|
30
|
-
access_key_id: access_key,
|
31
|
-
secret_access_key: secret_key,
|
32
|
-
http_method: operation.http_method,
|
33
|
-
endpoint: marketplace.host
|
34
|
-
)
|
35
|
-
|
36
|
-
signature = signer.sign_request(http_method: operation.http_method, url: endpoint, headers: headers, body: payload.to_json)
|
37
|
-
|
38
|
-
headers['Host'] = marketplace.host
|
39
|
-
headers['X-Amz-Date'] = signature.headers['x-amz-date']
|
40
|
-
headers['X-Amz-Content-Sha256']= signature.headers['x-amz-content-sha256']
|
41
|
-
headers['Authorization'] = signature.headers['authorization']
|
42
|
-
headers['Content-Type'] = 'application/json; charset=utf-8'
|
43
|
-
|
44
|
-
HTTP.headers(headers).post(endpoint, json: payload )
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|