erp_integration 0.54.0 → 0.55.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: 015dee8d29c0a8bcd763966f25c24b77efb9cd2e7ac4a1555aa104e9a708c2ec
4
- data.tar.gz: 92f5a27785677904bd7b0cd60fc5a033195ed99d64d9c16941fbb4d942db8b31
3
+ metadata.gz: 865d21dfcb8c0caaed6bb6e76151e019424294a04c5a553c68459cbda871278b
4
+ data.tar.gz: 5da7b05a69bc74a8dcfa508ebe2b7b544e5902b26398b6da552fd139f20170f1
5
5
  SHA512:
6
- metadata.gz: 526e86fb610c85d0b5c69f36e2cf1b1c396ff36e6f74c2db6d9764eae9eb1f076d9ed7771b5347ac3060bbdbd047777c1901c427351a280bcb26bf49b6edb269
7
- data.tar.gz: f876d9874077923090353f7e2c9d6766cae725fe1558345ba98f4d5cfc07495bb272f451205f04c6a957402fdf10bc756d69ad8792a55405c91a07ce856d5e4e
6
+ metadata.gz: ea5e4f2a3f0e8bec393964d050ef9db305d1b7859032989d6899750306eba46efba5627e741fc469b95c215a23a42e6f6fcdee7f418f1ddf3da2f276cb201629
7
+ data.tar.gz: 71db26f1be6f150c53f34591d7ca46f7f89805fb65b5f44258c6dac86067bb8752feae8a08c11bf5cc4f6c096e7b3749b511583d1e3cf536921463e0d829e385
data/README.md CHANGED
@@ -61,6 +61,47 @@ ErpIntegration::SalesOrder.api_keys_pool = '<your-api-key>'
61
61
  ErpIntegration::SalesOrder.api_keys_pool = ['<your-api-key1>', '<your-api-key2>']
62
62
  ```
63
63
 
64
+ ### Rate limiting
65
+
66
+ To manage the number of requests made to avoid rate limiting by the API provider, you can configure rate limiters in the ERP Integration gem. Each rate limiter should implement the `api_key_fragment` and `within_limit` methods.
67
+
68
+ ### Setting Up Rate Limiters
69
+ You can configure multiple rate limiters to be used for HTTP operations on the client.
70
+
71
+ ```ruby
72
+ # config/initializers/erp_integration.rb
73
+ ErpIntegration.configure do |config|
74
+ config.rate_limiters = [
75
+ MyRateLimiter.new(api_key_fragment: 'key1'),
76
+ MyRateLimiter.new(api_key_fragment: 'key2')
77
+ ]
78
+ end
79
+ ```
80
+
81
+ Each rate limiter must implement the following methods:
82
+ - `api_key_fragment`: This method should return a string that is used to identify the rate limiter by the API key.
83
+ - `within_limit`: This method should `yield` to the block if the rate limit is not exceeded.
84
+
85
+ ### Example Rate Limiter
86
+ Here is an example implementation of a rate limiter:
87
+
88
+ ```ruby
89
+ class MyRateLimiter
90
+ def initialize(api_key_fragment:)
91
+ @api_key_fragment = api_key_fragment
92
+ end
93
+
94
+ def api_key_fragment
95
+ @api_key_fragment
96
+ end
97
+
98
+ def within_limit
99
+ # Implement your rate limiting logic here
100
+ yield
101
+ end
102
+ end
103
+ ```
104
+
64
105
  ### Supported Query Methods
65
106
 
66
107
  After configuring the gem, one can easily query all the available ERP resources from the connected third-parties. In all cases, the API will return a collection of resources.
@@ -299,6 +299,18 @@ module ErpIntegration
299
299
  def product_option_adapter
300
300
  @product_option_adapter || :fulfil
301
301
  end
302
+
303
+ # Rate limiters that will be used for HTTP operations on Client
304
+ # to manage the number of requests made to avoid rate limiting by the API provider.
305
+ def rate_limiters
306
+ @rate_limiters ||= []
307
+ end
308
+
309
+ # Sets the rate limiters that will be used
310
+ # @raise [MissingMethodError] if the rate limiter object doesn't respond to the required methods.
311
+ def rate_limiters=(rate_limiters)
312
+ @rate_limiters = rate_limiters.each { |limiter| RateLimiter.validate!(limiter) }
313
+ end
302
314
  end
303
315
 
304
316
  # Returns ERP Integration's configuration.
@@ -48,7 +48,9 @@ module ErpIntegration
48
48
  raise ErpIntegration::Error, 'The Fulfil API key and/or base URL are missing.'
49
49
  end
50
50
 
51
- connection.public_send(action_name, "api/#{version}/#{path}", options).body
51
+ rate_limiter.within_limit do
52
+ connection.public_send(action_name, "api/#{version}/#{path}", options).body
53
+ end
52
54
  end
53
55
  end
54
56
 
@@ -64,6 +66,10 @@ module ErpIntegration
64
66
  api_keys_pool.current_key
65
67
  end
66
68
 
69
+ def rate_limiter
70
+ RateLimiter.find_by_api_key(api_key)
71
+ end
72
+
67
73
  def default_headers
68
74
  {
69
75
  'Accept': 'application/json',
@@ -43,6 +43,8 @@ module ErpIntegration
43
43
  @formatter.exception(exc) if @formatter.respond_to?(:exception)
44
44
  end
45
45
 
46
+ # @param [String] api_key
47
+ # @return [String] The last 4 characters of the API key
46
48
  def sanitize_api_key(api_key)
47
49
  api_key[-4..-1] if api_key
48
50
  end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ErpIntegration
4
+ class RateLimiter
5
+ class MissingMethodError < StandardError; end
6
+ # The `api_key_fragment` method should return a string that is used to identify
7
+ # the rate limiter by the API key.
8
+ #
9
+ # The `within_limit` method should yield to the block if the rate limit is not exceeded.
10
+ REQUIRED_METHODS = %i[api_key_fragment within_limit].freeze
11
+
12
+ class << self
13
+ # Validates that the rate limiter object responds to the required methods.
14
+ # It requires the `api_key_fragment` and `within_limit` methods to be present.
15
+ #
16
+ # @raise [MissingMethodError]
17
+ # @param rate_limiter [Object]
18
+ def validate!(rate_limiter)
19
+ REQUIRED_METHODS.each do |method|
20
+ next if rate_limiter.respond_to?(method)
21
+
22
+ raise MissingMethodError, "'#{rate_limiter.class}##{method}' method is required."
23
+ end
24
+ end
25
+
26
+ # Finds the rate limiter by the API key.
27
+ # If the API key is not found, it returns an unlimited rate limiter.
28
+ #
29
+ # @param api_key [String]
30
+ # @return [Object] The rate limiter object.
31
+ def find_by_api_key(api_key)
32
+ rate_limiters[api_key] || unlimited
33
+ end
34
+
35
+ # Returns an unlimited rate limiter.
36
+ #
37
+ # @return [RateLimiter::Unlimited] The unlimited rate limiter object.
38
+ def unlimited
39
+ @unlimited ||= Unlimited.new
40
+ end
41
+
42
+ private
43
+
44
+ # The `rate_limiters` hash stores the rate limiter objects found by the API key.
45
+ #
46
+ # @return [Hash] The rate limiters hash.
47
+ def rate_limiters
48
+ @rate_limiters ||= Hash.new do |h, api_key|
49
+ h[api_key] = ErpIntegration.config.rate_limiters.find do |rate_limiter|
50
+ api_key.end_with?(rate_limiter.api_key_fragment)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ # {Unlimited} is a rate limiter that allows all requests.
57
+ # When the rate limiter wasn't found by the API key, it defaults to this class.
58
+ # Or if the `rate_limiters` option is not set in the configuration.
59
+ class Unlimited
60
+ # Executes the block without any restrictions.
61
+ def within_limit
62
+ yield
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ErpIntegration
4
- VERSION = '0.54.0'
4
+ VERSION = '0.55.0'
5
5
  end
@@ -11,6 +11,7 @@ require 'json'
11
11
  require_relative 'erp_integration/version'
12
12
  require_relative 'erp_integration/errors'
13
13
  require_relative 'erp_integration/api_keys_pool'
14
+ require_relative 'erp_integration/rate_limiter'
14
15
  require_relative 'erp_integration/configuration'
15
16
 
16
17
  # Middleware
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erp_integration
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.54.0
4
+ version: 0.55.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Vermaas
@@ -329,6 +329,7 @@ files:
329
329
  - lib/erp_integration/purchase_order.rb
330
330
  - lib/erp_integration/purchase_order_line.rb
331
331
  - lib/erp_integration/purchase_request.rb
332
+ - lib/erp_integration/rate_limiter.rb
332
333
  - lib/erp_integration/resource.rb
333
334
  - lib/erp_integration/resources/errors.rb
334
335
  - lib/erp_integration/resources/persistence.rb
@@ -368,7 +369,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
368
369
  - !ruby/object:Gem::Version
369
370
  version: '0'
370
371
  requirements: []
371
- rubygems_version: 3.5.11
372
+ rubygems_version: 3.2.22
372
373
  signing_key:
373
374
  specification_version: 4
374
375
  summary: Connects Mejuri with third-party ERP vendors