rakuten_product_api 0.1.0 → 0.2.0
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/Gemfile.lock +3 -3
- data/README.md +27 -10
- data/lib/rakuten_product_api.rb +2 -0
- data/lib/rakuten_product_api/authenticate.rb +96 -0
- data/lib/rakuten_product_api/client.rb +26 -100
- data/lib/rakuten_product_api/item.rb +0 -2
- data/lib/rakuten_product_api/version.rb +1 -1
- data/rakuten_product_api.gemspec +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40785ddd9e89396be1d1e1831b0bda84092e17468308df8a9d381c15fa3124b4
|
4
|
+
data.tar.gz: 6bd0cc952f0a5f31a324b9d01f861c24dc8acb17c0745782079702db1f57856e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76780f846ad13f4098a3eb1eaca268eddb966053baed830f5a531857f33065998e379e840dd594d0d11124339e3885c1cd0719e7ed279e850f6f7c76d50dd917
|
7
|
+
data.tar.gz: 22a2d56430510a521f8b3ca7b3ff881eea656033b4ac56c7e7b540eb344c0e77fa80f7c73045951892641d576b8db6713dac722765931c8a7101635065717038
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rakuten_product_api (0.
|
5
|
-
|
6
|
-
nokogiri
|
4
|
+
rakuten_product_api (0.2.0)
|
5
|
+
nokogiri (~> 1)
|
7
6
|
|
8
7
|
GEM
|
9
8
|
remote: https://rubygems.org/
|
@@ -39,6 +38,7 @@ PLATFORMS
|
|
39
38
|
x86_64-darwin-20
|
40
39
|
|
41
40
|
DEPENDENCIES
|
41
|
+
byebug (~> 11)
|
42
42
|
minitest (~> 5.0)
|
43
43
|
rake (~> 13.0)
|
44
44
|
rakuten_product_api!
|
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# RakutenProductApi
|
2
2
|
|
3
|
-
To experiment with
|
3
|
+
To experiment with this library, run `bin/console` for an interactive prompt.
|
4
4
|
|
5
5
|
## API Documentation
|
6
6
|
|
7
|
-
The API documentation can be found at the following links.
|
7
|
+
The Rakuten Product API documentation can be found at the following links.
|
8
8
|
- [API Documentation PDF](https://developers.rakutenmarketing.com/console/registry/resource/_system/governance/apimgt/applicationdata/provider/RakutenMarketing/artifacts/API_Developer_Portal-Acquiring_Your_Access_Token_Guide.pdf)
|
9
9
|
- [API Overview](https://developers.rakutenmarketing.com/subscribe/)
|
10
10
|
- [API Keys](https://developers.rakutenmarketing.com/subscribe/site/pages/subscriptions.jag)
|
@@ -39,8 +39,6 @@ RakutenProductApi.configure do |config|
|
|
39
39
|
end
|
40
40
|
```
|
41
41
|
|
42
|
-
Additionally, you can configure a mid (Merchant ID). This will be applied to all requests and restrict queries to that merchant.
|
43
|
-
|
44
42
|
Once you have configured the library, you can create a client.
|
45
43
|
|
46
44
|
```ruby
|
@@ -50,8 +48,27 @@ client.username
|
|
50
48
|
=> "dkam"
|
51
49
|
```
|
52
50
|
|
53
|
-
|
54
|
-
|
51
|
+
This client should be threadsafe. Configuration values are local to your instance.
|
52
|
+
|
53
|
+
### Authentication
|
54
|
+
This library needs to query the API to retreive an `access_token` which has an `access_expires_at` time, prior to which, the library will refresh the token
|
55
|
+
|
56
|
+
You can initialise the library with the `access_token` and `access_expires_at` values to avoid this lookup. If the `access_expires_at` is in the past, the library will fetch the value so you can safely cache this value and use it without checking it's expiry.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
client = RakutenProductApi::Client.new(access_token: 'abcd1234', access_expires_at: 1613362973)
|
60
|
+
|
61
|
+
client.username
|
62
|
+
=> "dkam"
|
63
|
+
|
64
|
+
client.access_token
|
65
|
+
=> "abcd1234"
|
66
|
+
````
|
67
|
+
|
68
|
+
## Querying
|
69
|
+
### Search for keywords:
|
70
|
+
|
71
|
+
You can specify which merchants to query by using `mid: 38131`
|
55
72
|
|
56
73
|
```ruby
|
57
74
|
results = client.search(keyword: 'Murderbot', mid: 38131)
|
@@ -74,7 +91,9 @@ results.items[0].rrp
|
|
74
91
|
=> ["18.70", "AUD"]
|
75
92
|
```
|
76
93
|
|
77
|
-
Search for ISBNs:
|
94
|
+
### Search for ISBNs:
|
95
|
+
|
96
|
+
You can specify which merchants to query by using `mid: 38131`
|
78
97
|
|
79
98
|
```ruby
|
80
99
|
results = client.search(keyword: '9781501977824', mid: 38131)
|
@@ -93,8 +112,6 @@ The API also allows other attribute:
|
|
93
112
|
|
94
113
|
When using sort, you must also use sorttype ( 'asc' or 'dsc'). See the documentation for more.
|
95
114
|
|
96
|
-
This client should be threadsafe. Configuration values are local to your instance.
|
97
|
-
|
98
115
|
## TODO
|
99
116
|
|
100
117
|
This library implement the parts I need. For example, it doesn't handle paging through results as I don't need it, but I'm happy to accept pull request.
|
@@ -109,7 +126,7 @@ This library implement the parts I need. For example, it doesn't handle paging t
|
|
109
126
|
|
110
127
|
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.
|
111
128
|
|
112
|
-
If you create a file `config.rb`, it will be loaded by `bin/console`, allowing you to configure
|
129
|
+
If you create a file `config.rb`, it will be loaded by `bin/console`, allowing you to configure it automatically.
|
113
130
|
|
114
131
|
```ruby
|
115
132
|
RakutenProductApi.configure do |config|
|
data/lib/rakuten_product_api.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "json"
|
4
|
+
require "forwardable"
|
4
5
|
require_relative "rakuten_product_api/version"
|
6
|
+
require_relative "rakuten_product_api/authenticate"
|
5
7
|
require_relative "rakuten_product_api/client"
|
6
8
|
require_relative "rakuten_product_api/response"
|
7
9
|
require_relative "rakuten_product_api/item"
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "net/http"
|
3
|
+
require "net/https"
|
4
|
+
require "base64"
|
5
|
+
require "json"
|
6
|
+
|
7
|
+
module RakutenProductApi
|
8
|
+
class Authenticate
|
9
|
+
REFRESH_TOKEN_LEEWAY = 60 * 10 # Ten minutes prior to expiry we should refresh token
|
10
|
+
attr_accessor :sid, :username, :password, :consumer_key, :consumer_secret, :access_token, :access_expires_at
|
11
|
+
|
12
|
+
def initialize(sid: RakutenProductApi.sid,
|
13
|
+
username: RakutenProductApi.username,
|
14
|
+
password: RakutenProductApi.password,
|
15
|
+
consumer_key: RakutenProductApi.consumer_key,
|
16
|
+
consumer_secret: RakutenProductApi.consumer_secret,
|
17
|
+
access_token: nil,
|
18
|
+
access_expires_at: nil)
|
19
|
+
|
20
|
+
@sid = sid
|
21
|
+
@username = username
|
22
|
+
@password = password
|
23
|
+
@consumer_key = consumer_key
|
24
|
+
@consumer_secret = consumer_secret
|
25
|
+
@access_token = access_token
|
26
|
+
@access_expires_at = access_expires_at
|
27
|
+
end
|
28
|
+
|
29
|
+
def auth_header
|
30
|
+
ensure_authentication
|
31
|
+
"Bearer #{@access_token}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def request_auth_token
|
35
|
+
Base64.strict_encode64("#{@consumer_key}:#{@consumer_secret}").strip
|
36
|
+
end
|
37
|
+
|
38
|
+
def api_request_auth
|
39
|
+
res = auth_request(
|
40
|
+
"https://api.rakutenmarketing.com/token",
|
41
|
+
{ grant_type: "password", username: @username, password: @password, scope: @sid }
|
42
|
+
)
|
43
|
+
|
44
|
+
process_auth_response(res)
|
45
|
+
|
46
|
+
@access_expires_at = Time.now.to_i + @expires_in
|
47
|
+
end
|
48
|
+
|
49
|
+
def refresh_api_request_auth
|
50
|
+
res = auth_request(
|
51
|
+
"https://api.rakutenmarketing.com/token",
|
52
|
+
{ grant_type: "refresh_token", refresh_token: @refresh_token, scope: "Production" }
|
53
|
+
)
|
54
|
+
|
55
|
+
process_auth_response(res)
|
56
|
+
|
57
|
+
@access_expires_at = Time.now.to_i + @expires_in
|
58
|
+
end
|
59
|
+
|
60
|
+
def process_auth_response(res)
|
61
|
+
if res.code == "200"
|
62
|
+
doc = JSON.parse(res.body)
|
63
|
+
@expires_in = doc["expires_in"].to_i
|
64
|
+
@refresh_token = doc["refresh_token"]
|
65
|
+
@access_token = doc["access_token"]
|
66
|
+
else
|
67
|
+
puts "RESPONSE CODE #{res.code} received"
|
68
|
+
res
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def auth_request(url, payload)
|
73
|
+
uri = URI(url)
|
74
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
75
|
+
req = Net::HTTP::Post.new(uri)
|
76
|
+
req["Authorization"] = "Basic #{request_auth_token}"
|
77
|
+
|
78
|
+
req.set_form_data(payload)
|
79
|
+
http.request(req)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def ensure_authentication
|
84
|
+
if @access_expires_at.nil?
|
85
|
+
# puts "NIL: getting auth"
|
86
|
+
api_request_auth
|
87
|
+
elsif Time.now.to_i > @access_expires_at
|
88
|
+
# puts "EXPIRED: getting auth"
|
89
|
+
api_request_auth
|
90
|
+
elsif Time.now.to_i > (@access_expires_at + REFRESH_TOKEN_LEEWAY)
|
91
|
+
# puts "REFRESH LEEWAY: getting auth"
|
92
|
+
refresh_api_request_auth
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -6,105 +6,33 @@ require "nokogiri"
|
|
6
6
|
|
7
7
|
module RakutenProductApi
|
8
8
|
class Client
|
9
|
+
extend Forwardable
|
10
|
+
def_delegators :@authenticate, :access_token, :access_expires_at
|
9
11
|
REFRESH_TOKEN_LEEWAY = 60 * 10 # Ten minutes prior to expiry we should refresh token
|
10
12
|
|
11
|
-
attr_accessor :sid, :username, :password, :consumer_key, :consumer_secret, :
|
12
|
-
|
13
|
-
def initialize(sid:
|
14
|
-
username:
|
15
|
-
password:
|
16
|
-
consumer_key:
|
17
|
-
consumer_secret:
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
13
|
+
attr_accessor :sid, :username, :password, :consumer_key, :consumer_secret, :authenticate
|
14
|
+
|
15
|
+
def initialize(sid: RakutenProductApi.sid,
|
16
|
+
username: RakutenProductApi.username,
|
17
|
+
password: RakutenProductApi.password,
|
18
|
+
consumer_key: RakutenProductApi.consumer_key,
|
19
|
+
consumer_secret: RakutenProductApi.consumer_secret,
|
20
|
+
access_token: nil,
|
21
|
+
access_expires_at: nil)
|
22
|
+
|
23
|
+
@authenticate = Authenticate.new(sid: sid,
|
24
|
+
username: username,
|
25
|
+
password: password,
|
26
|
+
consumer_key: consumer_key,
|
27
|
+
consumer_secret: consumer_secret,
|
28
|
+
access_token: access_token,
|
29
|
+
access_expires_at: access_expires_at)
|
30
|
+
|
31
|
+
@sid = sid
|
32
|
+
@username = username
|
33
|
+
@password = password
|
34
|
+
@consumer_key = consumer_key
|
26
35
|
@consumer_secret = consumer_secret
|
27
|
-
@mid = mid
|
28
|
-
@sort = sort
|
29
|
-
@sorttype = sorttype
|
30
|
-
|
31
|
-
@auth_expires_at = nil
|
32
|
-
end
|
33
|
-
|
34
|
-
def default_params
|
35
|
-
dp = {}
|
36
|
-
dp[:mid] = @mid unless @mid.nil?
|
37
|
-
dp[:sort] = @sort unless @sort.nil?
|
38
|
-
dp[:sorttype] = @sorttype unless @sorttype.nil?
|
39
|
-
dp
|
40
|
-
end
|
41
|
-
|
42
|
-
def request_auth_token
|
43
|
-
Base64.strict_encode64("#{@consumer_key}:#{@consumer_secret}").strip
|
44
|
-
end
|
45
|
-
|
46
|
-
def request_auth_token_header
|
47
|
-
"Authorization: Basic #{request_auth_token}"
|
48
|
-
end
|
49
|
-
|
50
|
-
def api_request_auth
|
51
|
-
res = auth_request(
|
52
|
-
"https://api.rakutenmarketing.com/token",
|
53
|
-
{ grant_type: "password", username: @username, password: @password, scope: @sid }
|
54
|
-
)
|
55
|
-
|
56
|
-
process_auth_response(res)
|
57
|
-
|
58
|
-
@auth_expires_at = Time.now.to_i + @expires_in
|
59
|
-
end
|
60
|
-
|
61
|
-
def refresh_api_request_auth
|
62
|
-
res = auth_request(
|
63
|
-
"https://api.rakutenmarketing.com/token",
|
64
|
-
{ grant_type: "refresh_token", refresh_token: @refresh_token, scope: "Production" }
|
65
|
-
)
|
66
|
-
|
67
|
-
process_auth_response(res)
|
68
|
-
|
69
|
-
@auth_expires_at = Time.now.to_i + @expires_in
|
70
|
-
end
|
71
|
-
|
72
|
-
def process_auth_response(res)
|
73
|
-
if res.code == "200"
|
74
|
-
doc = JSON.parse(res.body)
|
75
|
-
@expires_in = doc["expires_in"].to_i
|
76
|
-
@refresh_token = doc["refresh_token"]
|
77
|
-
@access_token = doc["access_token"]
|
78
|
-
else
|
79
|
-
puts "RESPONSE CODE #{res.code} received"
|
80
|
-
res
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def auth_request(url, payload)
|
85
|
-
uri = URI(url)
|
86
|
-
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
87
|
-
req = Net::HTTP::Post.new(uri)
|
88
|
-
req["Authorization"] = "Basic #{request_auth_token}"
|
89
|
-
|
90
|
-
req.set_form_data(payload)
|
91
|
-
http.request(req)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def ensure_authentication
|
96
|
-
if @auth_expires_at.nil?
|
97
|
-
puts "NIL: getting auth"
|
98
|
-
api_request_auth
|
99
|
-
elsif Time.now.to_i > @auth_expires_at
|
100
|
-
puts "EXPIRED: getting auth"
|
101
|
-
api_request_auth
|
102
|
-
elsif Time.now.to_i > (@auth_expires_at + REFRESH_TOKEN_LEEWAY)
|
103
|
-
puts "REFRESH LEEWAY: getting auth"
|
104
|
-
refresh_api_request_auth
|
105
|
-
else
|
106
|
-
puts "VALID AUTH"
|
107
|
-
end
|
108
36
|
end
|
109
37
|
|
110
38
|
def search(keyword: nil, **options)
|
@@ -112,14 +40,12 @@ module RakutenProductApi
|
|
112
40
|
end
|
113
41
|
|
114
42
|
def api_request(payload)
|
115
|
-
|
116
|
-
|
117
|
-
params = default_params.merge(payload).map { |k, v| "#{k}=#{v}" }.join("&")
|
43
|
+
params = payload.map { |k, v| "#{k}=#{v}" }.join("&")
|
118
44
|
uri = URI("https://api.rakutenmarketing.com/productsearch/1.0?#{params}")
|
119
45
|
|
120
46
|
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
121
47
|
req = Net::HTTP::Get.new(uri)
|
122
|
-
req["Authorization"] =
|
48
|
+
req["Authorization"] = @authenticate.auth_header
|
123
49
|
req["Accept"] = "application/xml"
|
124
50
|
|
125
51
|
http.request(req)
|
data/rakuten_product_api.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
# Uncomment to register a new dependency of your gem
|
32
32
|
spec.add_dependency "nokogiri", "~> 1"
|
33
33
|
|
34
|
-
spec.add_development_dependency
|
34
|
+
spec.add_development_dependency "byebug", "~> 11"
|
35
35
|
|
36
36
|
# For more information and examples about making a new gem, checkout our
|
37
37
|
# guide at: https://bundler.io/guides/creating_gem.html
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rakuten_product_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Milne
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- bin/console
|
57
57
|
- bin/setup
|
58
58
|
- lib/rakuten_product_api.rb
|
59
|
+
- lib/rakuten_product_api/authenticate.rb
|
59
60
|
- lib/rakuten_product_api/client.rb
|
60
61
|
- lib/rakuten_product_api/item.rb
|
61
62
|
- lib/rakuten_product_api/response.rb
|
@@ -83,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
84
|
- !ruby/object:Gem::Version
|
84
85
|
version: '0'
|
85
86
|
requirements: []
|
86
|
-
rubygems_version: 3.
|
87
|
+
rubygems_version: 3.2.3
|
87
88
|
signing_key:
|
88
89
|
specification_version: 4
|
89
90
|
summary: Client for Rakutenmarketing.com.
|