x 0.10.0 → 0.11.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -28
  3. data/README.md +6 -2
  4. data/lib/x/authenticator.rb +8 -0
  5. data/lib/x/bearer_token_authenticator.rb +5 -3
  6. data/lib/x/cgi.rb +15 -0
  7. data/lib/x/client.rb +40 -40
  8. data/lib/x/connection.rb +39 -76
  9. data/lib/x/errors/bad_gateway.rb +5 -0
  10. data/lib/x/errors/{not_found_error.rb → bad_request.rb} +1 -1
  11. data/lib/x/errors/connection_exception.rb +5 -0
  12. data/lib/x/errors/error.rb +1 -6
  13. data/lib/x/errors/{forbidden_error.rb → forbidden.rb} +1 -1
  14. data/lib/x/errors/gateway_timeout.rb +5 -0
  15. data/lib/x/errors/{bad_request_error.rb → gone.rb} +1 -1
  16. data/lib/x/errors/network_error.rb +1 -1
  17. data/lib/x/errors/not_acceptable.rb +5 -0
  18. data/lib/x/errors/not_found.rb +5 -0
  19. data/lib/x/errors/payload_too_large.rb +5 -0
  20. data/lib/x/errors/service_unavailable.rb +5 -0
  21. data/lib/x/errors/too_many_redirects.rb +5 -0
  22. data/lib/x/errors/too_many_requests.rb +29 -0
  23. data/lib/x/errors/unauthorized.rb +5 -0
  24. data/lib/x/errors/unprocessable_entity.rb +5 -0
  25. data/lib/x/{media_upload.rb → media_uploader.rb} +12 -15
  26. data/lib/x/oauth_authenticator.rb +10 -15
  27. data/lib/x/redirect_handler.rb +26 -22
  28. data/lib/x/request_builder.rb +22 -35
  29. data/lib/x/response_parser.rb +92 -0
  30. data/lib/x/version.rb +1 -1
  31. data/sig/x.rbs +101 -87
  32. metadata +21 -13
  33. data/lib/x/errors/authentication_error.rb +0 -5
  34. data/lib/x/errors/payload_too_large_error.rb +0 -5
  35. data/lib/x/errors/service_unavailable_error.rb +0 -5
  36. data/lib/x/errors/too_many_redirects_error.rb +0 -5
  37. data/lib/x/errors/too_many_requests_error.rb +0 -29
  38. data/lib/x/response_handler.rb +0 -63
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a01e8a21951f3b998cfae0253c4d35c5412ac39f94681283b9059d4a196651e
4
- data.tar.gz: 5b4a5bb02d86b27391b005acb329893025222c20e9d0c99b88ed0d7e6322dc5e
3
+ metadata.gz: e5af820e6e3cd8b04becf201ad7af96c8d95d9206112673888f91c5ecf923187
4
+ data.tar.gz: 6f0f561be192153eca2cc7356c823c87bd98f0987256875892c0a2e9ea12b82d
5
5
  SHA512:
6
- metadata.gz: 8972eafdb4c041a61258f409fef5a93dc0ff56b70e5c8dd384e126652c1ab32a4e52dc56bd253d7c204ea6313e3ac321e93c7245c722c0d5491b59443c63435a
7
- data.tar.gz: 4a5dfb958b61b78cdcf9312250d3ba00182894241da1c3e9114f08f1029fb174be07043f607a864986e3d09d6d308dfac4d13549e2483d5746235b34c4dd05a2
6
+ metadata.gz: 8b208d5ba10604a34a57b0dd2ee5dc0992eb801cfbcc287a7f1b0d54444f214050a2c25b2ec6291868a8c35fff09260ad91a82641be830b87d3e6abf0207fc3e
7
+ data.tar.gz: 24c6a1083358b60065698320372d53404bab9c319aaad13b097508a7041653ac9d45aabd8e6f7a99204accddfc1beeeb2bce18bd67fa9ba816eb6282cbab4227
data/CHANGELOG.md CHANGED
@@ -1,69 +1,82 @@
1
+ ## [0.11.0] - 2023-10-24
2
+
3
+ * Add base Authenticator class (8c66ce2)
4
+ * Consistently use keyword arguments (3beb271)
5
+ * Use patern matching to build request (4d001c7)
6
+ * Rename ResponseHandler to ResponseParser (498e890)
7
+ * Rename methods to be more consistent (5b8c655)
8
+ * Rename MediaUpload to MediaUploader (84f0c15)
9
+ * Add mutant and kill mutants (b124968)
10
+ * Fix authentication bug with request URLs that contain spaces (8de3174)
11
+ * Refactor errors (853d39c)
12
+ * Make Connection class threadsafe (d95d285)
13
+
1
14
  ## [0.10.0] - 2023-10-08
2
15
 
3
- - Add media upload helper methods (6c6a267)
4
- - Add PayloadTooLargeError class (cd61850)
16
+ * Add media upload helper methods (6c6a267)
17
+ * Add PayloadTooLargeError class (cd61850)
5
18
 
6
19
  ## [0.9.1] - 2023-10-06
7
20
 
8
- - Allow successful empty responses (06bf7db)
9
- - Update default User-Agent string (296b36a)
10
- - Move query parameter escaping into RequestBuilder (56d6bd2)
21
+ * Allow successful empty responses (06bf7db)
22
+ * Update default User-Agent string (296b36a)
23
+ * Move query parameter escaping into RequestBuilder (56d6bd2)
11
24
 
12
25
  ## [0.9.0] - 2023-09-26
13
26
 
14
- - Add support for HTTP proxies (3740f4f)
27
+ * Add support for HTTP proxies (3740f4f)
15
28
 
16
29
  ## [0.8.1] - 2023-09-20
17
30
 
18
- - Fix bug where setting Connection#base_uri= doesn't update the HTTP client (d5a89db)
31
+ * Fix bug where setting Connection#base_uri= doesn't update the HTTP client (d5a89db)
19
32
 
20
33
  ## [0.8.0] - 2023-09-14
21
34
 
22
- - Add (back) bearer token authentication (62e141d)
23
- - Follow redirects (90a8c55)
24
- - Parse error responses with Content-Type: application/problem+json (0b697d9)
35
+ * Add (back) bearer token authentication (62e141d)
36
+ * Follow redirects (90a8c55)
37
+ * Parse error responses with Content-Type: application/problem+json (0b697d9)
25
38
 
26
39
  ## [0.7.1] - 2023-09-02
27
40
 
28
- - Fix bug in X::Authenticator#split_uri (ebc9d5f)
41
+ * Fix bug in X::Authenticator#split_uri (ebc9d5f)
29
42
 
30
43
  ## [0.7.0] - 2023-09-02
31
44
 
32
- - Remove OAuth gem (7c29bb1)
45
+ * Remove OAuth gem (7c29bb1)
33
46
 
34
47
  ## [0.6.0] - 2023-08-30
35
48
 
36
- - Add configurable debug output stream for logging (fd2d4b0)
37
- - Remove bearer token authentication (efff940)
38
- - Define RBS type signatures (d7f63ba)
49
+ * Add configurable debug output stream for logging (fd2d4b0)
50
+ * Remove bearer token authentication (efff940)
51
+ * Define RBS type signatures (d7f63ba)
39
52
 
40
53
  ## [0.5.1] - 2023-08-16
41
54
 
42
- - Fix bearer token authentication (1a1ca93)
55
+ * Fix bearer token authentication (1a1ca93)
43
56
 
44
57
  ## [0.5.0] - 2023-08-10
45
58
 
46
- - Add configurable write timeout (2a31f84)
47
- - Use built-in Gem::Version class (066e0b6)
59
+ * Add configurable write timeout (2a31f84)
60
+ * Use built-in Gem::Version class (066e0b6)
48
61
 
49
62
  ## [0.4.0] - 2023-08-06
50
63
 
51
- - Refactor Client into Authenticator, RequestBuilder, Connection, ResponseHandler (6bee1e9)
52
- - Add configurable open timeout (1000f9d)
53
- - Allow configuration of content type (f33a732)
64
+ * Refactor Client into Authenticator, RequestBuilder, Connection, ResponseHandler (6bee1e9)
65
+ * Add configurable open timeout (1000f9d)
66
+ * Allow configuration of content type (f33a732)
54
67
 
55
68
  ## [0.3.0] - 2023-08-04
56
69
 
57
- - Add accessors to X::Client (e61fa73)
58
- - Add configurable read timeout (41502b9)
59
- - Handle network-related errors (9ed1fb4)
60
- - Include response body in errors (a203e6a)
70
+ * Add accessors to X::Client (e61fa73)
71
+ * Add configurable read timeout (41502b9)
72
+ * Handle network-related errors (9ed1fb4)
73
+ * Include response body in errors (a203e6a)
61
74
 
62
75
  ## [0.2.0] - 2023-08-02
63
76
 
64
- - Allow configuration of base URL (4bc0531)
65
- - Improve error handling (14dc0cd)
77
+ * Allow configuration of base URL (4bc0531)
78
+ * Improve error handling (14dc0cd)
66
79
 
67
80
  ## [0.1.0] - 2023-08-02
68
81
 
69
- - Initial release
82
+ * Initial release
data/README.md CHANGED
@@ -130,11 +130,15 @@ Pull requests will only be accepted if they meet all the following criteria:
130
130
 
131
131
  bundle exec rake standard
132
132
 
133
- 2. For any new code paths, tests must be added to maintain 100% C0 code coverage. This can be verified with:
133
+ 2. 100% C0 code coverage. This can be verified with:
134
134
 
135
135
  bundle exec rake test
136
136
 
137
- 3. For any new classes or methods, RBS type signatures must be added (to sig/x.rbs). This can be verified with:
137
+ 3. 100% mutation coverage. This can be verified with:
138
+
139
+ bundle exec rake mutant
140
+
141
+ 4. RBS type signatures (in `sig/x.rbs`). This can be verified with:
138
142
 
139
143
  bundle exec rake steep
140
144
 
@@ -0,0 +1,8 @@
1
+ module X
2
+ # Base Authenticator class
3
+ class Authenticator
4
+ def header(_request)
5
+ {"Authorization" => ""}
6
+ end
7
+ end
8
+ end
@@ -1,14 +1,16 @@
1
+ require_relative "authenticator"
2
+
1
3
  module X
2
4
  # Handles bearer token authentication
3
- class BearerTokenAuthenticator
5
+ class BearerTokenAuthenticator < Authenticator
4
6
  attr_accessor :bearer_token
5
7
 
6
- def initialize(bearer_token)
8
+ def initialize(bearer_token:) # rubocop:disable Lint/MissingSuper
7
9
  @bearer_token = bearer_token
8
10
  end
9
11
 
10
12
  def header(_request)
11
- "Bearer #{bearer_token}"
13
+ {"Authorization" => "Bearer #{bearer_token}"}
12
14
  end
13
15
  end
14
16
  end
data/lib/x/cgi.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "cgi"
2
+
3
+ module X
4
+ # Namespaced CGI class
5
+ class CGI
6
+ # TODO: Replace CGI.escape with CGI.escapeURIComponent when support for Ruby 3.1 is dropped
7
+ def self.escape(value)
8
+ ::CGI.escape(value).gsub("+", "%20")
9
+ end
10
+
11
+ def self.escape_params(params)
12
+ params.map { |k, v| "#{k}=#{escape(v)}" }.join("&")
13
+ end
14
+ end
15
+ end
data/lib/x/client.rb CHANGED
@@ -1,87 +1,87 @@
1
1
  require "forwardable"
2
2
  require_relative "bearer_token_authenticator"
3
- require_relative "oauth_authenticator"
4
3
  require_relative "connection"
4
+ require_relative "oauth_authenticator"
5
5
  require_relative "redirect_handler"
6
6
  require_relative "request_builder"
7
- require_relative "response_handler"
7
+ require_relative "response_parser"
8
8
 
9
9
  module X
10
10
  # Main public interface
11
11
  class Client
12
12
  extend Forwardable
13
13
 
14
+ DEFAULT_BASE_URL = "https://api.twitter.com/2/".freeze
15
+
16
+ attr_accessor :base_url
17
+
14
18
  def_delegators :@authenticator, :bearer_token, :api_key, :api_key_secret, :access_token, :access_token_secret
15
19
  def_delegators :@authenticator, :bearer_token=, :api_key=, :api_key_secret=, :access_token=, :access_token_secret=
16
- def_delegators :@connection, :base_uri, :open_timeout, :read_timeout, :write_timeout, :debug_output
17
- def_delegators :@connection, :base_uri=, :open_timeout=, :read_timeout=, :write_timeout=, :debug_output=
18
- def_delegators :@request_builder, :content_type, :user_agent
19
- def_delegators :@request_builder, :content_type=, :user_agent=
20
- def_delegators :@response_handler, :array_class, :object_class
21
- def_delegators :@response_handler, :array_class=, :object_class=
22
- alias_method :base_url, :base_uri
23
- alias_method :base_url=, :base_uri=
24
- attr_accessor :authenticator, :connection, :request_builder, :redirect_handler, :response_handler
20
+ def_delegators :@connection, :open_timeout, :read_timeout, :write_timeout, :proxy_url, :debug_output
21
+ def_delegators :@connection, :open_timeout=, :read_timeout=, :write_timeout=, :proxy_url=, :debug_output=
22
+ def_delegators :@redirect_handler, :max_redirects
23
+ def_delegators :@redirect_handler, :max_redirects=
24
+ def_delegators :@response_parser, :array_class, :object_class
25
+ def_delegators :@response_parser, :array_class=, :object_class=
25
26
 
26
27
  def initialize(bearer_token: nil,
27
28
  api_key: nil, api_key_secret: nil, access_token: nil, access_token_secret: nil,
28
- base_url: Connection::DEFAULT_BASE_URL,
29
+ base_url: DEFAULT_BASE_URL,
29
30
  open_timeout: Connection::DEFAULT_OPEN_TIMEOUT,
30
31
  read_timeout: Connection::DEFAULT_READ_TIMEOUT,
31
32
  write_timeout: Connection::DEFAULT_WRITE_TIMEOUT,
32
33
  proxy_url: nil,
33
- content_type: RequestBuilder::DEFAULT_CONTENT_TYPE,
34
- user_agent: RequestBuilder::DEFAULT_USER_AGENT,
35
34
  debug_output: nil,
36
- array_class: ResponseHandler::DEFAULT_ARRAY_CLASS,
37
- object_class: ResponseHandler::DEFAULT_OBJECT_CLASS,
35
+ array_class: nil,
36
+ object_class: nil,
38
37
  max_redirects: RedirectHandler::DEFAULT_MAX_REDIRECTS)
39
38
 
39
+ @base_url = base_url
40
40
  initialize_authenticator(bearer_token, api_key, api_key_secret, access_token, access_token_secret)
41
- @connection = Connection.new(base_url: base_url, open_timeout: open_timeout, read_timeout: read_timeout,
41
+ @connection = Connection.new(open_timeout: open_timeout, read_timeout: read_timeout,
42
42
  write_timeout: write_timeout, debug_output: debug_output, proxy_url: proxy_url)
43
- @request_builder = RequestBuilder.new(content_type: content_type, user_agent: user_agent)
44
- @redirect_handler = RedirectHandler.new(@authenticator, @connection, @request_builder,
45
- max_redirects: max_redirects)
46
- @response_handler = ResponseHandler.new(array_class: array_class, object_class: object_class)
43
+ @request_builder = RequestBuilder.new
44
+ @redirect_handler = RedirectHandler.new(authenticator: @authenticator, connection: @connection,
45
+ request_builder: @request_builder, max_redirects: max_redirects)
46
+ @response_parser = ResponseParser.new(array_class: array_class, object_class: object_class)
47
47
  end
48
48
 
49
- def get(endpoint)
50
- send_request(:get, endpoint)
49
+ def get(endpoint, headers: {})
50
+ execute_request(:get, endpoint, headers: headers)
51
51
  end
52
52
 
53
- def post(endpoint, body = nil)
54
- send_request(:post, endpoint, body)
53
+ def post(endpoint, body = nil, headers: {})
54
+ execute_request(:post, endpoint, body: body, headers: headers)
55
55
  end
56
56
 
57
- def put(endpoint, body = nil)
58
- send_request(:put, endpoint, body)
57
+ def put(endpoint, body = nil, headers: {})
58
+ execute_request(:put, endpoint, body: body, headers: headers)
59
59
  end
60
60
 
61
- def delete(endpoint)
62
- send_request(:delete, endpoint)
61
+ def delete(endpoint, headers: {})
62
+ execute_request(:delete, endpoint, headers: headers)
63
63
  end
64
64
 
65
65
  private
66
66
 
67
67
  def initialize_authenticator(bearer_token, api_key, api_key_secret, access_token, access_token_secret)
68
68
  @authenticator = if bearer_token
69
- BearerTokenAuthenticator.new(bearer_token)
69
+ BearerTokenAuthenticator.new(bearer_token: bearer_token)
70
70
  elsif api_key && api_key_secret && access_token && access_token_secret
71
- OauthAuthenticator.new(api_key, api_key_secret, access_token, access_token_secret)
71
+ OAuthAuthenticator.new(api_key: api_key, api_key_secret: api_key_secret, access_token: access_token,
72
+ access_token_secret: access_token_secret)
72
73
  else
73
- raise ArgumentError,
74
- "Client must be initialized with either a bearer_token or " \
75
- "an api_key, api_key_secret, access_token, and access_token_secret"
74
+ Authenticator.new
76
75
  end
77
76
  end
78
77
 
79
- def send_request(http_method, endpoint, body = nil)
80
- uri = URI.join(base_uri.to_s, endpoint)
81
- request = @request_builder.build(@authenticator, http_method, uri, body: body)
82
- response = @connection.send_request(request)
83
- final_response = @redirect_handler.handle_redirects(response, request, base_uri)
84
- @response_handler.handle(final_response)
78
+ def execute_request(http_method, endpoint, headers:, body: nil)
79
+ uri = URI.join(base_url, endpoint)
80
+ request = @request_builder.build(authenticator: @authenticator, http_method: http_method, uri: uri, body: body,
81
+ headers: headers)
82
+ response = @connection.perform(request: request)
83
+ response = @redirect_handler.handle(response: response, request: request, base_url: base_url)
84
+ @response_parser.parse(response: response)
85
85
  end
86
86
  end
87
87
  end
data/lib/x/connection.rb CHANGED
@@ -9,12 +9,12 @@ module X
9
9
  class Connection
10
10
  extend Forwardable
11
11
 
12
- DEFAULT_BASE_URL = "https://api.twitter.com/2/".freeze
13
- DEFAULT_HOST = "https://api.twitter.com".freeze
12
+ DEFAULT_HOST = "api.twitter.com".freeze
14
13
  DEFAULT_PORT = 443
15
14
  DEFAULT_OPEN_TIMEOUT = 60 # seconds
16
15
  DEFAULT_READ_TIMEOUT = 60 # seconds
17
16
  DEFAULT_WRITE_TIMEOUT = 60 # seconds
17
+ DEFAULT_DEBUG_OUTPUT = File.open(File::NULL, "w")
18
18
  NETWORK_ERRORS = [
19
19
  Errno::ECONNREFUSED,
20
20
  Errno::ECONNRESET,
@@ -23,95 +23,58 @@ module X
23
23
  OpenSSL::SSL::SSLError
24
24
  ].freeze
25
25
 
26
- attr_reader :base_uri, :proxy_uri, :http_client
27
-
28
- def_delegators :@http_client, :open_timeout, :read_timeout, :write_timeout
29
- def_delegators :@http_client, :open_timeout=, :read_timeout=, :write_timeout=
30
- def_delegator :@http_client, :set_debug_output, :debug_output=
31
-
32
- def initialize(base_url: DEFAULT_BASE_URL, open_timeout: DEFAULT_OPEN_TIMEOUT,
33
- read_timeout: DEFAULT_READ_TIMEOUT, write_timeout: DEFAULT_WRITE_TIMEOUT, proxy_url: nil, debug_output: nil)
34
- @proxy_uri = URI(proxy_url) unless proxy_url.nil?
35
- self.base_uri = base_url
36
- apply_http_client_settings(
37
- open_timeout: open_timeout,
38
- read_timeout: read_timeout,
39
- write_timeout: write_timeout,
40
- debug_output: debug_output
41
- )
26
+ attr_accessor :open_timeout, :read_timeout, :write_timeout, :debug_output
27
+ attr_reader :proxy_url, :proxy_uri
28
+
29
+ def_delegator :proxy_uri, :host, :proxy_host
30
+ def_delegator :proxy_uri, :port, :proxy_port
31
+ def_delegator :proxy_uri, :user, :proxy_user
32
+ def_delegator :proxy_uri, :password, :proxy_pass
33
+
34
+ def initialize(open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT,
35
+ write_timeout: DEFAULT_WRITE_TIMEOUT, debug_output: DEFAULT_DEBUG_OUTPUT, proxy_url: nil)
36
+ @open_timeout = open_timeout
37
+ @read_timeout = read_timeout
38
+ @write_timeout = write_timeout
39
+ @debug_output = debug_output
40
+ self.proxy_url = proxy_url unless proxy_url.nil?
42
41
  end
43
42
 
44
- def send_request(request)
45
- response = @http_client.request(request)
43
+ def perform(request:)
44
+ host = request.uri.host || DEFAULT_HOST
45
+ port = request.uri.port || DEFAULT_PORT
46
+ http_client = build_http_client(host, port)
47
+ http_client.use_ssl = request.uri.scheme.eql?("https")
48
+ http_client.request(request)
46
49
  rescue *NETWORK_ERRORS => e
47
- raise NetworkError.new("Network error: #{e.message}", response: response)
50
+ raise NetworkError, "Network error: #{e}"
48
51
  end
49
52
 
50
- def base_uri=(base_url)
51
- base_uri = URI(base_url)
52
- raise ArgumentError, "Invalid base URL" unless base_uri.is_a?(URI::HTTPS) || base_uri.is_a?(URI::HTTP)
53
-
54
- @base_uri = base_uri
55
- update_http_client_settings
56
- end
53
+ def proxy_url=(proxy_url)
54
+ @proxy_url = proxy_url
55
+ proxy_uri = URI(proxy_url)
56
+ raise ArgumentError, "Invalid proxy URL: #{proxy_uri}" unless proxy_uri.is_a?(URI::HTTP)
57
57
 
58
- def debug_output
59
- @http_client.instance_variable_get(:@debug_output)
60
- end
61
-
62
- def configuration
63
- {
64
- base_url: base_uri.to_s,
65
- open_timeout: open_timeout,
66
- read_timeout: read_timeout,
67
- write_timeout: write_timeout,
68
- proxy_url: proxy_uri.to_s,
69
- debug_output: debug_output
70
- }
58
+ @proxy_uri = proxy_uri
71
59
  end
72
60
 
73
61
  private
74
62
 
75
- def apply_http_client_settings(open_timeout:, read_timeout:, write_timeout:, debug_output:)
76
- @http_client.open_timeout = open_timeout
77
- @http_client.read_timeout = read_timeout
78
- @http_client.write_timeout = write_timeout
79
- @http_client.set_debug_output(debug_output) if debug_output
80
- end
81
-
82
- def current_http_client_settings
83
- {
84
- open_timeout: @http_client.open_timeout,
85
- read_timeout: @http_client.read_timeout,
86
- write_timeout: @http_client.write_timeout,
87
- debug_output: debug_output
88
- }
89
- end
90
-
91
- def update_http_client_settings
92
- conditionally_apply_http_client_settings do
93
- host = @base_uri.host || DEFAULT_HOST
94
- port = @base_uri.port || DEFAULT_PORT
95
- @http_client = build_http_client(host: host, port: port)
96
- @http_client.use_ssl = @base_uri.scheme == "https"
97
- end
98
- end
99
-
100
- def build_http_client(host:, port:)
101
- if defined?(@proxy_uri)
102
- Net::HTTP.new(host, port, @proxy_uri&.host, @proxy_uri&.port, @proxy_uri&.user, @proxy_uri&.password)
63
+ def build_http_client(host = DEFAULT_HOST, port = DEFAULT_PORT)
64
+ http_client = if proxy_uri
65
+ Net::HTTP.new(host, port, proxy_host, proxy_port, proxy_user, proxy_pass)
103
66
  else
104
67
  Net::HTTP.new(host, port)
105
68
  end
69
+ configure_http_client(http_client)
106
70
  end
107
71
 
108
- def conditionally_apply_http_client_settings
109
- if defined?(@http_client)
110
- settings = current_http_client_settings
111
- yield
112
- apply_http_client_settings(**settings)
113
- else
114
- yield
72
+ def configure_http_client(http_client)
73
+ http_client.tap do |c|
74
+ c.open_timeout = open_timeout
75
+ c.read_timeout = read_timeout
76
+ c.write_timeout = write_timeout
77
+ c.set_debug_output(debug_output)
115
78
  end
116
79
  end
117
80
  end
@@ -0,0 +1,5 @@
1
+ require_relative "server_error"
2
+
3
+ module X
4
+ class BadGateway < ServerError; end
5
+ end
@@ -1,5 +1,5 @@
1
1
  require_relative "client_error"
2
2
 
3
3
  module X
4
- class NotFoundError < ClientError; end
4
+ class BadRequest < ClientError; end
5
5
  end
@@ -0,0 +1,5 @@
1
+ require_relative "client_error"
2
+
3
+ module X
4
+ class ConnectionException < ClientError; end
5
+ end
@@ -1,12 +1,7 @@
1
- require "json"
2
-
3
1
  module X
4
2
  # Base error class
5
3
  class Error < ::StandardError
6
- attr_reader :object
7
-
8
- def initialize(msg, response:)
9
- @object = JSON.parse(response.body) if response&.body && !response.body.empty?
4
+ def initialize(msg, _response = nil)
10
5
  super(msg)
11
6
  end
12
7
  end
@@ -1,5 +1,5 @@
1
1
  require_relative "client_error"
2
2
 
3
3
  module X
4
- class ForbiddenError < ClientError; end
4
+ class Forbidden < ClientError; end
5
5
  end
@@ -0,0 +1,5 @@
1
+ require_relative "server_error"
2
+
3
+ module X
4
+ class GatewayTimeout < ServerError; end
5
+ end
@@ -1,5 +1,5 @@
1
1
  require_relative "client_error"
2
2
 
3
3
  module X
4
- class BadRequestError < ClientError; end
4
+ class Gone < ClientError; end
5
5
  end
@@ -1,4 +1,4 @@
1
- require_relative "server_error"
1
+ require_relative "error"
2
2
 
3
3
  module X
4
4
  class NetworkError < Error; end
@@ -0,0 +1,5 @@
1
+ require_relative "client_error"
2
+
3
+ module X
4
+ class NotAcceptable < ClientError; end
5
+ end
@@ -0,0 +1,5 @@
1
+ require_relative "client_error"
2
+
3
+ module X
4
+ class NotFound < ClientError; end
5
+ end
@@ -0,0 +1,5 @@
1
+ require_relative "client_error"
2
+
3
+ module X
4
+ class PayloadTooLarge < ClientError; end
5
+ end
@@ -0,0 +1,5 @@
1
+ require_relative "server_error"
2
+
3
+ module X
4
+ class ServiceUnavailable < ServerError; end
5
+ end
@@ -0,0 +1,5 @@
1
+ require_relative "client_error"
2
+
3
+ module X
4
+ class TooManyRedirects < ClientError; end
5
+ end
@@ -0,0 +1,29 @@
1
+ require_relative "client_error"
2
+
3
+ module X
4
+ # Rate limit error
5
+ class TooManyRequests < ClientError
6
+ def initialize(msg, response)
7
+ @response = response
8
+ super(msg)
9
+ end
10
+
11
+ def limit
12
+ @response["x-rate-limit-limit"].to_i
13
+ end
14
+
15
+ def remaining
16
+ @response["x-rate-limit-remaining"].to_i
17
+ end
18
+
19
+ def reset_at
20
+ Time.at(@response["x-rate-limit-reset"].to_i)
21
+ end
22
+
23
+ def reset_in
24
+ [(reset_at - Time.now).ceil, 0].max
25
+ end
26
+
27
+ alias_method :retry_after, :reset_in
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ require_relative "client_error"
2
+
3
+ module X
4
+ class Unauthorized < ClientError; end
5
+ end
@@ -0,0 +1,5 @@
1
+ require_relative "client_error"
2
+
3
+ module X
4
+ class UnprocessableEntity < ClientError; end
5
+ end