vacuum 3.0.0 → 3.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +65 -24
- data/lib/vacuum.rb +5 -0
- data/lib/vacuum/locale.rb +50 -39
- data/lib/vacuum/matcher.rb +34 -1
- data/lib/vacuum/operation.rb +75 -0
- data/lib/vacuum/request.rb +59 -73
- data/lib/vacuum/response.rb +27 -4
- data/lib/vacuum/version.rb +1 -1
- data/test/cassettes/vacuum.yml +834 -253
- data/test/helper.rb +10 -0
- data/test/integration/test_requests.rb +105 -0
- data/test/integration_helper.rb +2 -4
- data/test/locales.yml.example +8 -0
- data/test/unit/test_locale.rb +43 -0
- data/test/unit/test_operation.rb +31 -0
- data/test/unit/test_request.rb +61 -0
- data/test/{vacuum → unit}/test_response.rb +5 -1
- metadata +41 -20
- data/test/locales.yml +0 -28
- data/test/vacuum/test_locale.rb +0 -35
- data/test/vacuum/test_request.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61ab29cce33477553968b592986abbc5de22f4885945032313a08dc89174c5c4
|
4
|
+
data.tar.gz: 01b3fddbc4f06899df06c595ff28dc0f812cca8d1b8604771614a077129d4a99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0d2aeb0b372920cca1f68268fe91f80630ca7272e1a6dadb25677aacad9a6ae86fa3ec2056ec5419f3167c2871ed9ffaf4a37dc248b8d0bc50ce51599a08e9a
|
7
|
+
data.tar.gz: 423a1e7ccd04499c3df8a05dde1da3a25f691ef4d846f64bd59ac55af55f9783239efdd537881a0c460900cad326fdd4c50041e0ce7bb9233cd3c934861227ba
|
data/README.md
CHANGED
@@ -1,20 +1,22 @@
|
|
1
1
|
# Vacuum
|
2
2
|
|
3
|
-
[![
|
3
|
+
[![Build](https://github.com/hakanensari/vacuum/workflows/build/badge.svg)](https://github.com/hakanensari/vacuum/actions)
|
4
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/ffbab4aa5fedf5780332/maintainability)](https://codeclimate.com/github/hakanensari/vacuum/maintainability)
|
5
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/ffbab4aa5fedf5780332/test_coverage)](https://codeclimate.com/github/hakanensari/vacuum/test_coverage)
|
4
6
|
|
5
|
-
Vacuum is a
|
7
|
+
Vacuum is a Ruby wrapper to [Amazon Product Advertising API 5.0](https://webservices.amazon.com/paapi5/documentation/). The API provides programmatic access to query product information on the Amazon marketplaces.
|
8
|
+
|
9
|
+
Cart Form functionality is not covered by this gem but is a primary focus on [carriage gem](https://github.com/skatkov/carriage)
|
10
|
+
|
11
|
+
You need to [register first](https://webservices.amazon.com/paapi5/documentation/register-for-pa-api.html) to use the API.
|
6
12
|
|
7
13
|
![vacuum](http://f.cl.ly/items/2k2X0e2u0G3k1c260D2u/vacuum.png)
|
8
14
|
|
9
15
|
## Usage
|
10
16
|
|
11
|
-
Vacuum follows the nomenclature of the Product Advertising API. The examples below are based on examples in the [Amazon docs](https://webservices.amazon.com/paapi5/documentation/).
|
12
|
-
|
13
17
|
### Getting Started
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
Create a request with your marketplace credentials, passing the two-letter country code of the marketplace.
|
19
|
+
Create a request with your marketplace credentials. Set the marketplace by passing its two-letter country code.
|
18
20
|
|
19
21
|
```ruby
|
20
22
|
request = Vacuum.new(marketplace: 'US',
|
@@ -23,17 +25,26 @@ request = Vacuum.new(marketplace: 'US',
|
|
23
25
|
partner_tag: '<PARTNER_TAG>')
|
24
26
|
```
|
25
27
|
|
26
|
-
|
28
|
+
You can now access the API using the available operations.
|
27
29
|
|
28
30
|
```ruby
|
29
|
-
|
31
|
+
response = request.search_items(title: 'lean startup')
|
32
|
+
puts response.to_h
|
33
|
+
```
|
34
|
+
|
35
|
+
Create a persistent connection to make multiple requests.
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
request.persistent
|
30
39
|
```
|
31
40
|
|
32
41
|
### Operations
|
33
42
|
|
43
|
+
Refer to the [API docs](https://webservices.amazon.com/paapi5/documentation/) for more detailed information.
|
44
|
+
|
34
45
|
#### GetBrowseNodes
|
35
46
|
|
36
|
-
Given a BrowseNodeId, the `GetBrowseNodes` operation returns details about the specified browse node like name, children and ancestors depending on the resources specified in the request. The names and browse node IDs of the children and ancestor browse nodes are also returned. `GetBrowseNodes` enables you to traverse the browse node hierarchy to find a browse node.
|
47
|
+
Given a BrowseNodeId, the `GetBrowseNodes` operation returns details about the specified browse node, like name, children and ancestors, depending on the resources specified in the request. The names and browse node IDs of the children and ancestor browse nodes are also returned. `GetBrowseNodes` enables you to traverse the browse node hierarchy to find a browse node.
|
37
48
|
|
38
49
|
```ruby
|
39
50
|
request.get_browse_nodes(
|
@@ -69,7 +80,7 @@ request.get_variations(
|
|
69
80
|
|
70
81
|
#### SearchItems
|
71
82
|
|
72
|
-
The `SearchItems` operation searches for items on Amazon based on a search query. The
|
83
|
+
The `SearchItems` operation searches for items on Amazon based on a search query. The API returns up to ten items per search request.
|
73
84
|
|
74
85
|
```ruby
|
75
86
|
request.search_items(keywords: 'harry potter')
|
@@ -77,18 +88,30 @@ request.search_items(keywords: 'harry potter')
|
|
77
88
|
|
78
89
|
### Response
|
79
90
|
|
80
|
-
|
91
|
+
Consume a response by parsing it into a Ruby hash.
|
81
92
|
|
82
93
|
```ruby
|
83
94
|
response.to_h
|
84
95
|
```
|
85
96
|
|
86
|
-
You can also `#dig` into
|
97
|
+
You can also `#dig` into this hash.
|
87
98
|
|
88
99
|
```ruby
|
89
100
|
response.dig('ItemsResult', 'Items')
|
90
101
|
```
|
91
102
|
|
103
|
+
### Logging
|
104
|
+
|
105
|
+
Write requests and reponses to a logger using the logging feature of the [HTTP gem](https://github.com/httprb/http) under the hood:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
require 'logger'
|
109
|
+
|
110
|
+
logger = Logger.new(STDOUT)
|
111
|
+
request.use(logging: {logger: logger})
|
112
|
+
```
|
113
|
+
|
114
|
+
### Bring your parser
|
92
115
|
You can extend Vacuum with a custom parser. Just swap the original with a class or module that responds to `.parse`.
|
93
116
|
|
94
117
|
```ruby
|
@@ -98,37 +121,55 @@ response.parse
|
|
98
121
|
|
99
122
|
If no custom parser is set, `Vacuum::Response#parse` delegates to `#to_h`.
|
100
123
|
|
101
|
-
### VCR
|
124
|
+
### VCR
|
102
125
|
|
103
|
-
If you are using [VCR](https://github.com/vcr/vcr) to test an app that accesses the
|
126
|
+
If you are using [VCR](https://github.com/vcr/vcr) to test an app that accesses the API, you can use the custom VCR matcher of Vacuum to stub requests.
|
104
127
|
|
105
128
|
```ruby
|
106
129
|
require 'vacuum/matcher'
|
107
130
|
|
108
|
-
|
131
|
+
# in your test
|
132
|
+
VCR.insert_cassette('cassette_name',
|
133
|
+
match_requests_on: [Vacuum::Matcher])
|
109
134
|
```
|
110
135
|
|
111
|
-
|
136
|
+
In RSpec, use the `:paapi` metadata.
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
require 'vacuum/matcher'
|
140
|
+
|
141
|
+
# in your test
|
142
|
+
it 'queries Amazon', :paapi do
|
143
|
+
end
|
144
|
+
```
|
112
145
|
|
113
|
-
|
146
|
+
## Development
|
147
|
+
|
148
|
+
Clone the repo and install dependencies.
|
149
|
+
|
150
|
+
```sh
|
151
|
+
bundle install
|
152
|
+
```
|
153
|
+
|
154
|
+
Tests and Rubocop should now pass as-is.
|
114
155
|
|
115
156
|
```sh
|
116
157
|
bundle exec rake
|
117
158
|
```
|
118
159
|
|
119
|
-
By default,
|
160
|
+
By default, the tests stub requests. Use the `RECORD` env var to record new interactions.
|
120
161
|
|
121
162
|
```sh
|
122
|
-
bundle exec
|
163
|
+
RECORD=true bundle exec rake test
|
123
164
|
```
|
124
165
|
|
125
|
-
You can
|
166
|
+
You can set the `LIVE` env var to run all tests against live data.
|
126
167
|
|
127
|
-
```
|
128
|
-
bundle exec
|
168
|
+
```sh
|
169
|
+
LIVE=true bundle exec rake test
|
129
170
|
```
|
130
171
|
|
131
|
-
In either case,
|
172
|
+
In either case, add actual API credentials to a [`locales.yml`](https://github.com/hakanensari/vacuum/blob/master/test/locales.yml.example) file under `test`.
|
132
173
|
|
133
174
|
## Getting Help
|
134
175
|
|
data/lib/vacuum.rb
CHANGED
data/lib/vacuum/locale.rb
CHANGED
@@ -1,53 +1,64 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Vacuum
|
4
|
-
# The target
|
5
|
-
#
|
4
|
+
# The target locale
|
5
|
+
#
|
6
|
+
# @see https://webservices.amazon.com/paapi5/documentation/common-request-parameters.html#host-and-region
|
6
7
|
class Locale
|
7
|
-
|
8
|
+
# Raised when the provided marketplace does not correspond to an existing
|
9
|
+
# Amazon locale
|
10
|
+
class NotFound < KeyError; end
|
8
11
|
|
9
|
-
|
12
|
+
HOSTS_AND_REGIONS = {
|
13
|
+
au: ['webservices.amazon.com.au', 'us-west-2'],
|
14
|
+
br: ['webservices.amazon.com.br', 'us-east-1'],
|
15
|
+
ca: ['webservices.amazon.ca', 'us-east-1'],
|
16
|
+
fr: ['webservices.amazon.fr', 'eu-west-1'],
|
17
|
+
de: ['webservices.amazon.de', 'eu-west-1'],
|
18
|
+
in: ['webservices.amazon.in', 'eu-west-1'],
|
19
|
+
it: ['webservices.amazon.it', 'eu-west-1'],
|
20
|
+
jp: ['webservices.amazon.co.jp', 'us-west-2'],
|
21
|
+
mx: ['webservices.amazon.com.mx', 'us-east-1'],
|
22
|
+
nl: ['webservices.amazon.nl', 'eu-west-1'],
|
23
|
+
sg: ['webservices.amazon.sg', 'us-west-2'],
|
24
|
+
es: ['webservices.amazon.es', 'eu-west-1'],
|
25
|
+
tr: ['webservices.amazon.com.tr', 'eu-west-1'],
|
26
|
+
ae: ['webservices.amazon.ae', 'eu-west-1'],
|
27
|
+
gb: ['webservices.amazon.co.uk', 'eu-west-1'],
|
28
|
+
us: ['webservices.amazon.com', 'us-east-1']
|
29
|
+
}.freeze
|
30
|
+
private_constant :HOSTS_AND_REGIONS
|
10
31
|
|
11
|
-
|
12
|
-
|
13
|
-
|
32
|
+
# @return [String]
|
33
|
+
attr_reader :host, :region, :access_key, :secret_key, :partner_tag,
|
34
|
+
:partner_type
|
14
35
|
|
15
|
-
|
36
|
+
# Creates a locale
|
37
|
+
#
|
38
|
+
# @param [Symbol,String] marketplace
|
39
|
+
# @param [String] access_key
|
40
|
+
# @param [String] secret_key
|
41
|
+
# @param [String] partner_tag
|
42
|
+
# @param [String] partner_type
|
43
|
+
# @raise [NotFound] if marketplace is not found
|
44
|
+
def initialize(marketplace, access_key:, secret_key:, partner_tag:,
|
45
|
+
partner_type: 'Associates')
|
46
|
+
@host, @region = find_host_and_region(marketplace)
|
47
|
+
@access_key = access_key
|
48
|
+
@secret_key = secret_key
|
49
|
+
@partner_tag = partner_tag
|
50
|
+
@partner_type = partner_type
|
16
51
|
end
|
17
52
|
|
18
|
-
|
19
|
-
@code = code
|
20
|
-
@domain = domain
|
21
|
-
@region = region
|
22
|
-
end
|
53
|
+
private
|
23
54
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
55
|
+
def find_host_and_region(marketplace)
|
56
|
+
marketplace = marketplace.to_sym.downcase
|
57
|
+
marketplace = :gb if marketplace == :uk
|
27
58
|
|
28
|
-
|
29
|
-
|
59
|
+
HOSTS_AND_REGIONS.fetch(marketplace)
|
60
|
+
rescue KeyError
|
61
|
+
raise NotFound, "marketplace not found: :#{marketplace}"
|
30
62
|
end
|
31
|
-
|
32
|
-
def build_url(operation)
|
33
|
-
"https://#{endpoint}/paapi5/#{operation.downcase}"
|
34
|
-
end
|
35
|
-
|
36
|
-
@all = [
|
37
|
-
[:au, 'amazon.com.au', 'us-west-2'],
|
38
|
-
[:br, 'amazon.com.br', 'us-east-1'],
|
39
|
-
[:ca, 'amazon.ca', 'us-east-1'],
|
40
|
-
[:fr, 'amazon.fr', 'eu-west-1'],
|
41
|
-
[:de, 'amazon.de', 'eu-west-1'],
|
42
|
-
[:in, 'amazon.in', 'eu-west-1'],
|
43
|
-
[:it, 'amazon.it', 'eu-west-1'],
|
44
|
-
[:jp, 'amazon.co.jp', 'us-west-2'],
|
45
|
-
[:mx, 'amazon.com.mx', 'us-east-1'],
|
46
|
-
[:es, 'amazon.es', 'eu-west-1'],
|
47
|
-
[:tr, 'amazon.com.tr', 'eu-west-1'],
|
48
|
-
[:ae, 'amazon.ae', 'eu-west-1'],
|
49
|
-
[:gb, 'amazon.co.uk', 'eu-west-1'],
|
50
|
-
[:us, 'amazon.com', 'us-east-1']
|
51
|
-
].map { |attributes| new(*attributes) }
|
52
63
|
end
|
53
64
|
end
|
data/lib/vacuum/matcher.rb
CHANGED
@@ -4,20 +4,35 @@ require 'json'
|
|
4
4
|
|
5
5
|
module Vacuum
|
6
6
|
# Custom VCR matcher for stubbing calls to the Product Advertising API
|
7
|
-
#
|
7
|
+
#
|
8
|
+
# The matcher is not required by default.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# require 'vacuum/matcher'
|
12
|
+
#
|
13
|
+
# # in your test
|
14
|
+
# VCR.insert_cassette('cassette_name',
|
15
|
+
# match_requests_on: [Vacuum::Matcher])
|
16
|
+
#
|
17
|
+
# @see https://relishapp.com/vcr/vcr/v/5-0-0/docs/request-matching/register-and-use-a-custom-matcher
|
8
18
|
class Matcher
|
9
19
|
IGNORED_KEYS = %w[PartnerTag].freeze
|
20
|
+
private_constant :IGNORED_KEYS
|
10
21
|
|
22
|
+
# @!visibility private
|
11
23
|
attr_reader :requests
|
12
24
|
|
25
|
+
# @!visibility private
|
13
26
|
def self.call(*requests)
|
14
27
|
new(*requests).compare
|
15
28
|
end
|
16
29
|
|
30
|
+
# @!visibility private
|
17
31
|
def initialize(*requests)
|
18
32
|
@requests = requests
|
19
33
|
end
|
20
34
|
|
35
|
+
# @!visibility private
|
21
36
|
def compare
|
22
37
|
uris.reduce(:==) && bodies.reduce(:==)
|
23
38
|
end
|
@@ -38,3 +53,21 @@ module Vacuum
|
|
38
53
|
end
|
39
54
|
end
|
40
55
|
end
|
56
|
+
|
57
|
+
# :nocov:
|
58
|
+
if defined?(RSpec)
|
59
|
+
RSpec.configure do |config|
|
60
|
+
config.around do |example|
|
61
|
+
if example.metadata[:paapi]
|
62
|
+
metadata = example.metadata[:paapi]
|
63
|
+
metadata = {} if metadata == true
|
64
|
+
example.metadata[:vcr] = metadata.merge(
|
65
|
+
match_requests_on: [Vacuum::Matcher]
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
example.run
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
# :nocov:
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'aws-sigv4'
|
4
|
+
require 'http'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module Vacuum
|
8
|
+
# An Amazon Product Advertising API operation
|
9
|
+
class Operation
|
10
|
+
# @!visibility private
|
11
|
+
attr_reader :locale, :name, :params
|
12
|
+
|
13
|
+
# Creates a new operation
|
14
|
+
#
|
15
|
+
# @param [String] name
|
16
|
+
# @param [Hash] params
|
17
|
+
# @param [Locale] locale
|
18
|
+
def initialize(name, params:, locale:)
|
19
|
+
@name = name
|
20
|
+
@params = params
|
21
|
+
@locale = locale
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Hash]
|
25
|
+
def headers
|
26
|
+
signature.headers.merge(
|
27
|
+
'x-amz-target' =>
|
28
|
+
"com.amazon.paapi5.v1.ProductAdvertisingAPIv1.#{name}",
|
29
|
+
'content-encoding' => 'amz-1.0',
|
30
|
+
'content-type' => 'application/json; charset=utf-8'
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [String]
|
35
|
+
def body
|
36
|
+
@body ||= build_body
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [String]
|
40
|
+
def url
|
41
|
+
@url ||= build_url
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def build_body
|
47
|
+
hsh = { 'PartnerTag' => locale.partner_tag,
|
48
|
+
'PartnerType' => locale.partner_type }
|
49
|
+
|
50
|
+
params.each do |key, val|
|
51
|
+
key = key.to_s.split('_')
|
52
|
+
.map { |word| word == 'asin' ? 'ASIN' : word.capitalize }.join
|
53
|
+
hsh[key] = val
|
54
|
+
end
|
55
|
+
|
56
|
+
JSON.generate(hsh)
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_url
|
60
|
+
"https://#{locale.host}/paapi5/#{name.downcase}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def signature
|
64
|
+
signer.sign_request(http_method: 'POST', url: url, body: body)
|
65
|
+
end
|
66
|
+
|
67
|
+
def signer
|
68
|
+
Aws::Sigv4::Signer.new(service: 'ProductAdvertisingAPI',
|
69
|
+
region: locale.region,
|
70
|
+
access_key_id: locale.access_key,
|
71
|
+
secret_access_key: locale.secret_key,
|
72
|
+
http_method: 'POST', endpoint: locale.host)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/vacuum/request.rb
CHANGED
@@ -1,38 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'httpi'
|
5
|
-
require 'json'
|
3
|
+
require 'http'
|
6
4
|
|
7
5
|
require 'vacuum/locale'
|
6
|
+
require 'vacuum/operation'
|
8
7
|
require 'vacuum/response'
|
9
8
|
|
10
9
|
module Vacuum
|
11
10
|
# A request to the Amazon Product Advertising API
|
12
11
|
class Request
|
13
|
-
|
14
|
-
|
12
|
+
# @return [HTTP::Client]
|
13
|
+
attr_reader :client
|
15
14
|
|
16
|
-
# @
|
17
|
-
attr_reader :
|
15
|
+
# @return [Locale]
|
16
|
+
attr_reader :locale
|
17
|
+
|
18
|
+
# @return [Operation]
|
19
|
+
attr_reader :operation
|
18
20
|
|
19
21
|
# Creates a new request
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@
|
30
|
-
@
|
31
|
-
@partner_tag = partner_tag
|
32
|
-
@partner_type = partner_type
|
22
|
+
#
|
23
|
+
# @overload initialize(marketplace: :us, access_key:, secret_key:, partner_tag:, partner_type:)
|
24
|
+
# @param [Symbol,String] marketplace
|
25
|
+
# @param [String] access_key
|
26
|
+
# @param [String] secret_key
|
27
|
+
# @param [String] partner_tag
|
28
|
+
# @param [String] partner_type
|
29
|
+
# @raise [Locale::NotFound] if marketplace is not found
|
30
|
+
def initialize(marketplace: :us, **args)
|
31
|
+
@locale = Locale.new(marketplace, **args)
|
32
|
+
@client = HTTP::Client.new
|
33
33
|
end
|
34
34
|
|
35
35
|
# Returns details about specified browse nodes
|
36
|
+
#
|
36
37
|
# @see https://webservices.amazon.com/paapi5/documentation/getbrowsenodes.html
|
37
38
|
# @overload get_browse_nodes(browse_node_ids:, languages_of_preference: nil, marketplace: nil, partner_tag: nil, partner_type: nil, resources: nil)
|
38
39
|
# @param [Array<String,Integer>,String,Integer] browse_node_ids
|
@@ -48,6 +49,7 @@ module Vacuum
|
|
48
49
|
end
|
49
50
|
|
50
51
|
# Returns the attributes of one or more items
|
52
|
+
#
|
51
53
|
# @see https://webservices.amazon.com/paapi5/documentation/get-items.html
|
52
54
|
# @overload get_items(condition: nil, currency_of_preference: nil, item_id_type: nil, item_ids:, languages_of_preference: nil, marketplace: nil, merchant: nil, offer_count: nil, partner_tag: nil, partner_type: nil, resources: nil)
|
53
55
|
# @param [String,nil] condition
|
@@ -69,6 +71,7 @@ module Vacuum
|
|
69
71
|
|
70
72
|
# Returns a set of items that are the same product, but differ according to
|
71
73
|
# a consistent theme
|
74
|
+
#
|
72
75
|
# @see https://webservices.amazon.com/paapi5/documentation/get-variations.html
|
73
76
|
# @overload get_variations(asin:, condition: nil, currency_of_preference: nil, languages_of_preference: nil, marketplace: nil, merchant: nil, offer_count: nil, partner_tag: nil, partner_type: nil, resources: nil, variation_count: nil, variation_page: nil)
|
74
77
|
# @param [String] asin
|
@@ -89,6 +92,7 @@ module Vacuum
|
|
89
92
|
end
|
90
93
|
|
91
94
|
# Searches for items on Amazon based on a search query
|
95
|
+
#
|
92
96
|
# @see https://webservices.amazon.com/paapi5/documentation/search-items.html
|
93
97
|
# @overload search_items(actor: nil, artist: nil, author: nil, availability: nil, brand: nil, browse_node_id: nil, condition: nil, currency_of_preference: nil, delivery_flags: nil, item_count: nil, item_page: nil, keywords: nil, languages_of_preference: nil, marketplace: nil, max_price: nil, merchant: nil, min_price: nil, min_reviews_rating: nil, min_savings_percent: nil, offer_count: nil, partner_tag: nil, partner_type: nil, resources: nil, search_index: nil, sort_by: nil, title: nil)
|
94
98
|
# @param [String,nil] actor
|
@@ -119,69 +123,51 @@ module Vacuum
|
|
119
123
|
request('SearchItems', params)
|
120
124
|
end
|
121
125
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
126
|
+
# Flags as persistent
|
127
|
+
#
|
128
|
+
# @param [Integer] timeout
|
129
|
+
# @return [self]
|
130
|
+
def persistent(timeout: 5)
|
131
|
+
host = "https://#{locale.host}"
|
132
|
+
@client = client.persistent(host, timeout: timeout)
|
127
133
|
|
128
|
-
|
129
|
-
headers: request_headers(operation, signature),
|
130
|
-
url: locale.build_url(operation),
|
131
|
-
body: body
|
132
|
-
)
|
133
|
-
|
134
|
-
Response.new(HTTPI.post(request))
|
134
|
+
self
|
135
135
|
end
|
136
136
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
137
|
+
# @!method use(*features)
|
138
|
+
# Turn on {https://github.com/httprb/http HTTP} features
|
139
|
+
#
|
140
|
+
# @param features
|
141
|
+
# @return [self]
|
142
|
+
#
|
143
|
+
# @!method via(*proxy)
|
144
|
+
# Make a request through an HTTP proxy
|
145
|
+
#
|
146
|
+
# @param [Array] proxy
|
147
|
+
# @raise [HTTP::Request::Error] if HTTP proxy is invalid
|
148
|
+
# @return [self]
|
149
|
+
%i[timeout via through headers use].each do |method_name|
|
150
|
+
define_method(method_name) do |*args, &block|
|
151
|
+
@client = client.send(method_name, *args, &block)
|
152
|
+
end
|
144
153
|
end
|
145
154
|
|
146
|
-
|
147
|
-
headers(operation).merge(
|
148
|
-
'Content-Type' => 'application/json; charset=utf-8',
|
149
|
-
'Authorization' => signature.headers['authorization'],
|
150
|
-
'X-Amz-Content-Sha256' => signature.headers['x-amz-content-sha256'],
|
151
|
-
'X-Amz-Date' => signature.headers['x-amz-date'],
|
152
|
-
'Host' => locale.endpoint
|
153
|
-
)
|
154
|
-
end
|
155
|
+
private
|
155
156
|
|
156
|
-
def
|
157
|
-
|
158
|
-
|
159
|
-
'Content-Encoding' => 'amz-1.0'
|
160
|
-
}
|
161
|
-
end
|
157
|
+
def validate_keywords(params)
|
158
|
+
return unless params[:keywords]
|
159
|
+
return if params[:keywords].is_a?(String)
|
162
160
|
|
163
|
-
|
164
|
-
Aws::Sigv4::Signer.new(
|
165
|
-
service: SERVICE,
|
166
|
-
region: locale.region,
|
167
|
-
access_key_id: access_key,
|
168
|
-
secret_access_key: secret_key,
|
169
|
-
http_method: 'POST',
|
170
|
-
endpoint: locale.endpoint
|
171
|
-
)
|
161
|
+
raise ArgumentError, ':keyword argument expects a String'
|
172
162
|
end
|
173
163
|
|
174
|
-
def
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
key = key.to_s.split('_')
|
180
|
-
.map { |word| word == 'asin' ? 'ASIN' : word.capitalize }.join
|
181
|
-
hsh[key] = val
|
182
|
-
end
|
164
|
+
def request(operation_name, params)
|
165
|
+
validate_keywords(params)
|
166
|
+
@operation = Operation.new(operation_name, params: params, locale: locale)
|
167
|
+
response = client.headers(operation.headers)
|
168
|
+
.post(operation.url, body: operation.body)
|
183
169
|
|
184
|
-
|
170
|
+
Response.new(response)
|
185
171
|
end
|
186
172
|
end
|
187
173
|
end
|