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 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.