rakuten_product_api 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|