erp_integration 0.53.1 → 0.55.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/README.md +43 -2
- data/lib/erp_integration/configuration.rb +16 -4
- data/lib/erp_integration/fulfil/api_resource.rb +1 -1
- data/lib/erp_integration/fulfil/client.rb +12 -12
- data/lib/erp_integration/middleware/logger.rb +2 -0
- data/lib/erp_integration/rate_limiter.rb +66 -0
- data/lib/erp_integration/version.rb +1 -1
- data/lib/erp_integration.rb +1 -0
- 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: 865d21dfcb8c0caaed6bb6e76151e019424294a04c5a553c68459cbda871278b
|
4
|
+
data.tar.gz: 5da7b05a69bc74a8dcfa508ebe2b7b544e5902b26398b6da552fd139f20170f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea5e4f2a3f0e8bec393964d050ef9db305d1b7859032989d6899750306eba46efba5627e741fc469b95c215a23a42e6f6fcdee7f418f1ddf3da2f276cb201629
|
7
|
+
data.tar.gz: 71db26f1be6f150c53f34591d7ca46f7f89805fb65b5f44258c6dac86067bb8752feae8a08c11bf5cc4f6c096e7b3749b511583d1e3cf536921463e0d829e385
|
data/README.md
CHANGED
@@ -26,7 +26,7 @@ To configure the gem, create an initializer and add the following lines:
|
|
26
26
|
# config/initializers/erp_integration.rb
|
27
27
|
ErpIntegration.configure do |config|
|
28
28
|
config.fulfil_api_keys = '<your-api-key>'
|
29
|
-
config.
|
29
|
+
config.fulfil_base_url = '<your-base-url>'
|
30
30
|
end
|
31
31
|
```
|
32
32
|
|
@@ -35,7 +35,7 @@ You can configure multiple API keys, to enable rotation mechanism (see ["API key
|
|
35
35
|
# config/initializers/erp_integration.rb
|
36
36
|
ErpIntegration.configure do |config|
|
37
37
|
config.fulfil_api_keys = ['<your-api-key1>', '<your-api-key2>']
|
38
|
-
config.
|
38
|
+
config.fulfil_base_url = '<your-base-url>'
|
39
39
|
end
|
40
40
|
```
|
41
41
|
|
@@ -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.
|
@@ -14,13 +14,13 @@ module ErpIntegration
|
|
14
14
|
class Configuration
|
15
15
|
# The `fulfil_api_keys` sets a single or a list of API keys to use
|
16
16
|
# in the `FulfilClient` to authorize the requests to the Fulfil API endpoints.
|
17
|
-
# @return [Array<
|
17
|
+
# @return [Array<String>] The API keys for Fulfil.
|
18
18
|
attr_accessor :fulfil_api_keys
|
19
19
|
|
20
|
-
# The `
|
20
|
+
# The `fulfil_base_url` is used by the `FulfilClient` to connect to
|
21
21
|
# the right Fulfil API endpoints.
|
22
|
-
# @return [String] The
|
23
|
-
attr_accessor :
|
22
|
+
# @return [String] The base URL for Fulfil.
|
23
|
+
attr_accessor :fulfil_base_url
|
24
24
|
|
25
25
|
# Allows configuring an adapter for the `BillOfMaterial` resource. When
|
26
26
|
# none is configured, it will default to Fulfil.
|
@@ -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.
|
@@ -3,21 +3,15 @@
|
|
3
3
|
module ErpIntegration
|
4
4
|
module Fulfil
|
5
5
|
class Client
|
6
|
-
attr_reader :api_keys_pool, :
|
6
|
+
attr_reader :api_keys_pool, :base_url
|
7
7
|
attr_writer :connection, :faraday_adapter, :rotate_statuses
|
8
8
|
|
9
|
-
def initialize(api_keys_pool:,
|
9
|
+
def initialize(api_keys_pool:, base_url:, logger: nil)
|
10
10
|
@api_keys_pool = api_keys_pool
|
11
|
-
@
|
11
|
+
@base_url = base_url.strip
|
12
12
|
@logger = logger
|
13
13
|
end
|
14
14
|
|
15
|
-
# Generates the url prefix for the Faraday connection client.
|
16
|
-
# @return [String] The base url for the Fulfil HTTP client
|
17
|
-
def base_url
|
18
|
-
"https://#{merchant_id}.fulfil.io/"
|
19
|
-
end
|
20
|
-
|
21
15
|
# Sets the default adapter for the Faraday Connection.
|
22
16
|
# @return [Symbol] The default Faraday adapter
|
23
17
|
def faraday_adapter
|
@@ -50,11 +44,13 @@ module ErpIntegration
|
|
50
44
|
|
51
45
|
%i[delete get patch put post].each do |action_name|
|
52
46
|
define_method(action_name) do |path, options = {}|
|
53
|
-
if api_key.nil? ||
|
54
|
-
raise ErpIntegration::Error, 'The Fulfil API key and/or
|
47
|
+
if api_key.nil? || base_url.nil?
|
48
|
+
raise ErpIntegration::Error, 'The Fulfil API key and/or base URL are missing.'
|
55
49
|
end
|
56
50
|
|
57
|
-
|
51
|
+
rate_limiter.within_limit do
|
52
|
+
connection.public_send(action_name, "api/#{version}/#{path}", options).body
|
53
|
+
end
|
58
54
|
end
|
59
55
|
end
|
60
56
|
|
@@ -70,6 +66,10 @@ module ErpIntegration
|
|
70
66
|
api_keys_pool.current_key
|
71
67
|
end
|
72
68
|
|
69
|
+
def rate_limiter
|
70
|
+
RateLimiter.find_by_api_key(api_key)
|
71
|
+
end
|
72
|
+
|
73
73
|
def default_headers
|
74
74
|
{
|
75
75
|
'Accept': 'application/json',
|
@@ -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
|
data/lib/erp_integration.rb
CHANGED
@@ -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,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: erp_integration
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.55.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Vermaas
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -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
|