fulfil-io 0.8.1 → 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 +10 -0
- data/README.md +20 -1
- data/lib/fulfil/client.rb +16 -13
- 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,13 @@
|
|
|
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
|
+
|
|
1
11
|
## 0.8.1
|
|
2
12
|
|
|
3
13
|
* Add logger to configuration by @cdmwebs in https://github.com/knowndecimal/fulfil/pull/49
|
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
|
|
@@ -177,7 +179,8 @@ module Fulfil
|
|
|
177
179
|
def client
|
|
178
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
|
|
@@ -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
|