fulfil-io 0.8.0 → 0.9.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/CHANGELOG.md +41 -0
- data/README.md +20 -1
- data/lib/fulfil/client.rb +17 -14
- data/lib/fulfil/configuration.rb +14 -0
- data/lib/fulfil/response_handler.rb +51 -15
- data/lib/fulfil/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: df8251caaf1131da686f385b8ccfa716259b5af29859f84d1236d469cc88b5b9
|
|
4
|
+
data.tar.gz: 695fb3d9c099d2c43d44e23cfc41cd21405be94bef8d1181383526f487ed7660
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 69dc9272022c7d312b3bfcc701cc8fa9814bb1d1a64da76c0e5e938676810a46df5f50ed25f573e05260a221faf968cabe6bbe095eee50463f2cd9c9a263bdb0
|
|
7
|
+
data.tar.gz: e5f4b528beea3306899269b647fc34c6981a7950fc664d536eca4458963eb92c01039e101a48ac692ac45e574a27a79bf9ea417103d5c31abbaabc82dac7bd0b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
## 0.9.0
|
|
2
|
+
|
|
3
|
+
* Drop legacy Ruby support and require Ruby 3.2+.
|
|
4
|
+
* Update CI matrix to supported Rubies (3.2, 3.3, 3.4).
|
|
5
|
+
* Migrate coverage uploads from Code Climate to Qlty.
|
|
6
|
+
* Update runtime and development dependencies.
|
|
7
|
+
* Auth cleanup: support explicit `api_key` while keeping backwards compatibility for `headers: { 'X-API-KEY' => ... }`.
|
|
8
|
+
* Fix auth selection to ignore blank tokens and correctly fall back to API key authentication.
|
|
9
|
+
* Improve HTTP error handling and rescue ordering so specific connection/response errors are raised correctly.
|
|
10
|
+
|
|
11
|
+
## 0.8.1
|
|
12
|
+
|
|
13
|
+
* Add logger to configuration by @cdmwebs in https://github.com/knowndecimal/fulfil/pull/49
|
|
14
|
+
|
|
15
|
+
## 0.8.0
|
|
16
|
+
|
|
17
|
+
* Add rubocop by @stefanvermaas in https://github.com/knowndecimal/fulfil/pull/35
|
|
18
|
+
* Remove _now from testing example by @swanny85 in https://github.com/knowndecimal/fulfil/pull/32
|
|
19
|
+
* Add SimpleCov for test coverage by @cdmwebs in https://github.com/knowndecimal/fulfil/pull/38
|
|
20
|
+
* Add support for Fulfil sale duplication by @swanny85 in https://github.com/knowndecimal/fulfil/pull/48
|
|
21
|
+
|
|
22
|
+
## 0.6.1
|
|
23
|
+
|
|
24
|
+
* Fixes a typo in the examples of the readme by @stefanvermaas in https://github.com/knowndecimal/fulfil/pull/25
|
|
25
|
+
* Fix requiring gemfiles manually by @stefanvermaas in https://github.com/knowndecimal/fulfil/pull/27
|
|
26
|
+
|
|
27
|
+
## 0.6.0
|
|
28
|
+
|
|
29
|
+
* Streamline the usage of environment variables. by @stefanvermaas in https://github.com/knowndecimal/fulfil/pull/18
|
|
30
|
+
* Update http requirement from ~> 4.4.1 to >= 4.4.1, < 5.1.0 by @dependabot in https://github.com/knowndecimal/fulfil/pull/12
|
|
31
|
+
* Remove extremely precise User-Agent from mocks. by @stefanvermaas in https://github.com/knowndecimal/fulfil/pull/20
|
|
32
|
+
* Use GitHub Actions instead of Travis CI and Circle CI by @stefanvermaas in https://github.com/knowndecimal/fulfil/pull/21
|
|
33
|
+
* Remove persistent connection and client caching by @stefanvermaas in https://github.com/knowndecimal/fulfil/pull/22
|
|
34
|
+
* Add rate limit detection by @stefanvermaas in https://github.com/knowndecimal/fulfil/pull/24
|
|
35
|
+
|
|
36
|
+
## 0.5.0
|
|
37
|
+
|
|
38
|
+
* Better response parsing and error handling.
|
|
39
|
+
* Documentation updates.
|
|
40
|
+
* Add release script.
|
|
41
|
+
|
|
1
42
|
## 0.4.9
|
|
2
43
|
|
|
3
44
|
* Add client tests and stub with Webmock.
|
data/README.md
CHANGED
|
@@ -32,7 +32,8 @@ Environment variables:
|
|
|
32
32
|
|
|
33
33
|
- **FULFIL_SUBDOMAIN:** - always required to use the gem.
|
|
34
34
|
- **FULFIL_OAUTH_TOKEN:** required for oauth bearer authentication
|
|
35
|
-
- **FULFIL_API_KEY:** required for authentication via the `X-API-KEY` request
|
|
35
|
+
- **FULFIL_API_KEY:** required for authentication via the `X-API-KEY` request
|
|
36
|
+
header. This is used with the Personal Access Token authentication method.
|
|
36
37
|
|
|
37
38
|
> **Note:** When `FULFIL_OAUTH_TOKEN` is present, the `FULFIL_API_KEY` will be ignored. So,
|
|
38
39
|
if oauth doesn't work, returning an Unauthorized error, to use the
|
|
@@ -72,6 +73,24 @@ pp sales
|
|
|
72
73
|
# "rec_name"=>""}]
|
|
73
74
|
```
|
|
74
75
|
|
|
76
|
+
To configure a client without using environment variables, pass them as arguments:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
client = Fulfil::Client.new(
|
|
80
|
+
subdomain: 'test',
|
|
81
|
+
api_key: '123'
|
|
82
|
+
)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
With an OAuth token:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
client = Fulfil::Client.new(
|
|
89
|
+
subdomain: 'test',
|
|
90
|
+
token: '123'
|
|
91
|
+
)
|
|
92
|
+
```
|
|
93
|
+
|
|
75
94
|
### Count
|
|
76
95
|
|
|
77
96
|
```ruby
|
data/lib/fulfil/client.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Fulfil
|
|
|
11
11
|
class Client
|
|
12
12
|
class InvalidClientError < StandardError
|
|
13
13
|
def message
|
|
14
|
-
'Client is not configured correctly.'
|
|
14
|
+
super || 'Client is not configured correctly.'
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -23,12 +23,19 @@ module Fulfil
|
|
|
23
23
|
|
|
24
24
|
class ResponseError < StandardError; end
|
|
25
25
|
|
|
26
|
-
def initialize(subdomain: SUBDOMAIN, token: oauth_token,
|
|
26
|
+
def initialize(subdomain: SUBDOMAIN, token: oauth_token, api_key: API_KEY, headers: nil, debug: false)
|
|
27
27
|
@subdomain = subdomain
|
|
28
|
-
@token = token
|
|
29
28
|
@debug = debug
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
|
|
30
|
+
normalized_api_key = api_key || headers&.[]('X-API-KEY') || headers&.[]('X-Api-Key')
|
|
31
|
+
|
|
32
|
+
if !token.to_s.empty?
|
|
33
|
+
@token = token
|
|
34
|
+
elsif !normalized_api_key.to_s.empty?
|
|
35
|
+
@api_key = normalized_api_key
|
|
36
|
+
else
|
|
37
|
+
raise InvalidClientError, 'No token or API key provided.'
|
|
38
|
+
end
|
|
32
39
|
|
|
33
40
|
raise InvalidClientError if invalid?
|
|
34
41
|
end
|
|
@@ -150,21 +157,16 @@ module Fulfil
|
|
|
150
157
|
end
|
|
151
158
|
|
|
152
159
|
def request(endpoint:, verb: :get, **args)
|
|
153
|
-
raise InvalidClientError if invalid?
|
|
154
|
-
|
|
155
160
|
response = client.request(verb, endpoint, args)
|
|
156
161
|
Fulfil::ResponseHandler.new(response).verify!
|
|
157
162
|
|
|
158
163
|
response.parse
|
|
159
|
-
rescue HTTP::Error => e
|
|
160
|
-
puts e
|
|
161
|
-
raise UnknownHTTPError, 'Unhandled HTTP error encountered'
|
|
162
164
|
rescue HTTP::ConnectionError => e
|
|
163
|
-
puts "Couldn't connect"
|
|
164
165
|
raise ConnectionError, "Can't connect to #{base_url}"
|
|
165
166
|
rescue HTTP::ResponseError => e
|
|
166
167
|
raise ResponseError, "Can't process response: #{e}"
|
|
167
|
-
|
|
168
|
+
rescue HTTP::Error => e
|
|
169
|
+
raise UnknownHTTPError, 'Unhandled HTTP error encountered'
|
|
168
170
|
# If configured, the client will wait whenever the `RateLimitExceeded` exception
|
|
169
171
|
# is raised. Check `Fulfil::Configuration` for more details.
|
|
170
172
|
rescue RateLimitExceeded => e
|
|
@@ -175,9 +177,10 @@ module Fulfil
|
|
|
175
177
|
end
|
|
176
178
|
|
|
177
179
|
def client
|
|
178
|
-
client = HTTP.use(logging: @debug ? { logger:
|
|
180
|
+
client = HTTP.use(logging: @debug ? { logger: config.logger } : {})
|
|
179
181
|
client = client.auth("Bearer #{@token}") if @token
|
|
180
|
-
client.headers(@
|
|
182
|
+
client = client.headers({ 'X-API-KEY': @api_key }) if @api_key
|
|
183
|
+
client
|
|
181
184
|
end
|
|
182
185
|
|
|
183
186
|
def config
|
data/lib/fulfil/configuration.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'logger'
|
|
4
|
+
|
|
3
5
|
module Fulfil
|
|
4
6
|
# The `Fulfil::Configuration` contains the available configuration options
|
|
5
7
|
# for the `Fulfil` gem.
|
|
@@ -22,9 +24,21 @@ module Fulfil
|
|
|
22
24
|
# @return [Proc, nil]
|
|
23
25
|
attr_accessor :rate_limit_notification_handler
|
|
24
26
|
|
|
27
|
+
# Allows the client to configure a logger. Logs are output to $stderr by default.
|
|
28
|
+
#
|
|
29
|
+
# @example Use a logger to log the API rate limit hits
|
|
30
|
+
# Fulfil.configure do |config|
|
|
31
|
+
# config.logger = Logger.new($stderr)
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# @return [Logger, nil]
|
|
35
|
+
#
|
|
36
|
+
attr_accessor :logger
|
|
37
|
+
|
|
25
38
|
def initialize
|
|
26
39
|
@retry_on_rate_limit = false
|
|
27
40
|
@retry_on_rate_limit_wait = 1
|
|
41
|
+
@logger = Logger.new($stderr)
|
|
28
42
|
end
|
|
29
43
|
|
|
30
44
|
def retry_on_rate_limit?
|
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Fulfil
|
|
4
|
-
# The `Fulfil::ResponseHandler`
|
|
5
|
-
# encounters an HTTP status code that indicates an error, it
|
|
4
|
+
# The `Fulfil::ResponseHandler` parses the HTTP response from Fulfil. If it
|
|
5
|
+
# encounters an HTTP status code that indicates an error, it raises an internal
|
|
6
6
|
# exception that the consumer can catch.
|
|
7
|
-
#
|
|
8
|
-
# @example
|
|
9
|
-
# Fulfil::ResponseHandler.new(@response).verify!
|
|
10
|
-
# => true
|
|
11
|
-
#
|
|
12
|
-
# Fulfil::ResponseHandler.new(@response).verify!
|
|
13
|
-
# => Fulfil::Error::BadRequest
|
|
14
7
|
class ResponseHandler
|
|
15
8
|
HTTP_ERROR_CODES = {
|
|
16
9
|
400 => Fulfil::HttpError::BadRequest,
|
|
@@ -44,18 +37,61 @@ module Fulfil
|
|
|
44
37
|
def verify_http_status_code!
|
|
45
38
|
return true unless @status_code >= 400
|
|
46
39
|
|
|
40
|
+
payload = response_body
|
|
47
41
|
raise HTTP_ERROR_CODES.fetch(@status_code, Fulfil::HttpError).new(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
body: @response.body,
|
|
51
|
-
headers: @response.headers,
|
|
52
|
-
status: @response.status
|
|
53
|
-
}
|
|
42
|
+
response_error_message(payload),
|
|
43
|
+
response_error_metadata(payload)
|
|
54
44
|
)
|
|
55
45
|
end
|
|
56
46
|
|
|
47
|
+
def response_error_message(payload)
|
|
48
|
+
body = payload.is_a?(Hash) ? payload : {}
|
|
49
|
+
|
|
50
|
+
code = body['code']
|
|
51
|
+
type = body['type']
|
|
52
|
+
message = first_present(
|
|
53
|
+
body['error_description'],
|
|
54
|
+
body.dig('error', 'message'),
|
|
55
|
+
body['message'],
|
|
56
|
+
body['description'],
|
|
57
|
+
body['detail'],
|
|
58
|
+
body.dig('errors', 0, 'message')
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
return "Fulfil request failed (HTTP #{@status_code})" if message.nil?
|
|
62
|
+
|
|
63
|
+
message_parts = []
|
|
64
|
+
message_parts << "[#{code}]" if present?(code)
|
|
65
|
+
message_parts << "#{type}:" if present?(type)
|
|
66
|
+
message_parts << message
|
|
67
|
+
message_parts.join(' ')
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def response_error_metadata(payload)
|
|
71
|
+
body = payload.is_a?(Hash) ? payload : {}
|
|
72
|
+
|
|
73
|
+
{
|
|
74
|
+
body: @response.body,
|
|
75
|
+
parsed_body: payload,
|
|
76
|
+
headers: @response.headers,
|
|
77
|
+
status: @response.status,
|
|
78
|
+
code: body['code'],
|
|
79
|
+
type: body['type'],
|
|
80
|
+
message: body['message'],
|
|
81
|
+
description: body['description']
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
57
85
|
def response_body
|
|
58
86
|
@response_body ||= @response.parse
|
|
59
87
|
end
|
|
88
|
+
|
|
89
|
+
def present?(value)
|
|
90
|
+
!(value.nil? || value.to_s.strip.empty?)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def first_present(*values)
|
|
94
|
+
values.find { |value| present?(value) }
|
|
95
|
+
end
|
|
60
96
|
end
|
|
61
97
|
end
|
data/lib/fulfil/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fulfil-io
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Moore
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date:
|
|
13
|
+
date: 2026-03-03 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: http
|
|
@@ -21,7 +21,7 @@ dependencies:
|
|
|
21
21
|
version: 4.4.1
|
|
22
22
|
- - "<"
|
|
23
23
|
- !ruby/object:Gem::Version
|
|
24
|
-
version:
|
|
24
|
+
version: '6.0'
|
|
25
25
|
type: :runtime
|
|
26
26
|
prerelease: false
|
|
27
27
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -31,7 +31,7 @@ dependencies:
|
|
|
31
31
|
version: 4.4.1
|
|
32
32
|
- - "<"
|
|
33
33
|
- !ruby/object:Gem::Version
|
|
34
|
-
version:
|
|
34
|
+
version: '6.0'
|
|
35
35
|
description:
|
|
36
36
|
email:
|
|
37
37
|
- chris@knowndecimal.com
|
|
@@ -72,14 +72,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
72
72
|
requirements:
|
|
73
73
|
- - ">="
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '2
|
|
75
|
+
version: '3.2'
|
|
76
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
77
|
requirements:
|
|
78
78
|
- - ">="
|
|
79
79
|
- !ruby/object:Gem::Version
|
|
80
80
|
version: '0'
|
|
81
81
|
requirements: []
|
|
82
|
-
rubygems_version: 3.
|
|
82
|
+
rubygems_version: 3.4.10
|
|
83
83
|
signing_key:
|
|
84
84
|
specification_version: 4
|
|
85
85
|
summary: Interact with the Fulfil.io API
|