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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1fd5a4ee5820366f85f0c1266d2f0edd5ce8375343e64cccd6c55ab95274619
4
- data.tar.gz: 56e0a89e406c5d7e16cf7b9cc80be336eba8d9ae1fc1c01c94d6088d980c8815
3
+ metadata.gz: 40785ddd9e89396be1d1e1831b0bda84092e17468308df8a9d381c15fa3124b4
4
+ data.tar.gz: 6bd0cc952f0a5f31a324b9d01f861c24dc8acb17c0745782079702db1f57856e
5
5
  SHA512:
6
- metadata.gz: 67867a384786c0c5f316fb228a130c5e8593a8d7e18639d305de3849a7d78a467c19c57f5ec1406bc0e5ef674031c4834c280abf9a974bf9b5f0f86fb53b7994
7
- data.tar.gz: e27d9b209f5f6ac43cbd9ae8af25a0ccb74d343ec89e11601604cbbbae85f538521db537a85ec4bafb235b306777b18ba0fd0c91839ad926a8b914495df40061
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.1.0)
5
- byebug
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 that code, run `bin/console` for an interactive prompt.
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
- ### Search
54
- Search for keywords:
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 keys and markets.
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|
@@ -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, :mid, :auth_expires_at
12
-
13
- def initialize(sid: RakutenProductApi.sid,
14
- username: RakutenProductApi.username,
15
- password: RakutenProductApi.password,
16
- consumer_key: RakutenProductApi.consumer_key,
17
- consumer_secret: RakutenProductApi.consumer_secret,
18
- mid: RakutenProductApi.mid,
19
- sort: RakutenProductApi.sort,
20
- sorttype: RakutenProductApi.sorttype)
21
-
22
- @sid = sid
23
- @username = username
24
- @password = password
25
- @consumer_key = consumer_key
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
- ensure_authentication
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"] = "Bearer #{@access_token}"
48
+ req["Authorization"] = @authenticate.auth_header
123
49
  req["Accept"] = "application/xml"
124
50
 
125
51
  http.request(req)
@@ -1,5 +1,3 @@
1
- require "forwardable"
2
-
3
1
  module RakutenProductApi
4
2
  class Item
5
3
  extend Forwardable
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RakutenProductApi
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -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 'byebug', '~> 11'
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.1.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.1.4
87
+ rubygems_version: 3.2.3
87
88
  signing_key:
88
89
  specification_version: 4
89
90
  summary: Client for Rakutenmarketing.com.