x 0.9.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -27
  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 -37
  8. data/lib/x/connection.rb +42 -65
  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 -9
  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/internal_server_error.rb +5 -0
  17. data/lib/x/errors/network_error.rb +1 -1
  18. data/lib/x/errors/not_acceptable.rb +5 -0
  19. data/lib/x/errors/not_found.rb +5 -0
  20. data/lib/x/errors/payload_too_large.rb +5 -0
  21. data/lib/x/errors/service_unavailable.rb +5 -0
  22. data/lib/x/errors/too_many_redirects.rb +5 -0
  23. data/lib/x/errors/too_many_requests.rb +29 -0
  24. data/lib/x/errors/unauthorized.rb +5 -0
  25. data/lib/x/errors/unprocessable_entity.rb +5 -0
  26. data/lib/x/media_uploader.rb +122 -0
  27. data/lib/x/oauth_authenticator.rb +10 -15
  28. data/lib/x/redirect_handler.rb +26 -24
  29. data/lib/x/request_builder.rb +22 -28
  30. data/lib/x/response_parser.rb +92 -0
  31. data/lib/x/version.rb +1 -1
  32. data/sig/x.rbs +160 -71
  33. metadata +22 -11
  34. data/lib/x/errors/authentication_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 -54
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2906018cf3e05342abe1bc6c938f3d1b3cf9d1d84c3813a96a11b693fbe0960
4
- data.tar.gz: f84f47e1a9ea06b101712ae1f9fd7198d71b2cbc7487a654b8442dd13e3244e0
3
+ metadata.gz: e5af820e6e3cd8b04becf201ad7af96c8d95d9206112673888f91c5ecf923187
4
+ data.tar.gz: 6f0f561be192153eca2cc7356c823c87bd98f0987256875892c0a2e9ea12b82d
5
5
  SHA512:
6
- metadata.gz: 2c98c3ea7e22d0b023a328207c9599dca0f74b54d5ed05eea04378c5c2ed5a2803799b7dcafa54d041d3b7dac8b3e08c8559d4cacb03b2419796368fa153401e
7
- data.tar.gz: 36c0faa98a5f6657a88ce770924e2669f91fcea2985b38f1c82dc0766d0c5a5cf6a4b0342d4684f5b679b41dc76f5fa94b791a6468b6f0514c28f6d70864b41a
6
+ metadata.gz: 8b208d5ba10604a34a57b0dd2ee5dc0992eb801cfbcc287a7f1b0d54444f214050a2c25b2ec6291868a8c35fff09260ad91a82641be830b87d3e6abf0207fc3e
7
+ data.tar.gz: 24c6a1083358b60065698320372d53404bab9c319aaad13b097508a7041653ac9d45aabd8e6f7a99204accddfc1beeeb2bce18bd67fa9ba816eb6282cbab4227
data/CHANGELOG.md CHANGED
@@ -1,66 +1,82 @@
1
- ## [Unreleased]
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
+
14
+ ## [0.10.0] - 2023-10-08
15
+
16
+ * Add media upload helper methods (6c6a267)
17
+ * Add PayloadTooLargeError class (cd61850)
2
18
 
3
19
  ## [0.9.1] - 2023-10-06
4
20
 
5
- - Allow successful empty responses (06bf7db)
6
- - Update default User-Agent string (296b36a)
7
- - 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)
8
24
 
9
25
  ## [0.9.0] - 2023-09-26
10
26
 
11
- - Add support for HTTP proxies (3740f4f)
27
+ * Add support for HTTP proxies (3740f4f)
12
28
 
13
29
  ## [0.8.1] - 2023-09-20
14
30
 
15
- - 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)
16
32
 
17
33
  ## [0.8.0] - 2023-09-14
18
34
 
19
- - Add (back) bearer token authentication (62e141d)
20
- - Follow redirects (90a8c55)
21
- - 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)
22
38
 
23
39
  ## [0.7.1] - 2023-09-02
24
40
 
25
- - Fix bug in X::Authenticator#split_uri (ebc9d5f)
41
+ * Fix bug in X::Authenticator#split_uri (ebc9d5f)
26
42
 
27
43
  ## [0.7.0] - 2023-09-02
28
44
 
29
- - Remove OAuth gem (7c29bb1)
45
+ * Remove OAuth gem (7c29bb1)
30
46
 
31
47
  ## [0.6.0] - 2023-08-30
32
48
 
33
- - Add configurable debug output stream for logging (fd2d4b0)
34
- - Remove bearer token authentication (efff940)
35
- - 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)
36
52
 
37
53
  ## [0.5.1] - 2023-08-16
38
54
 
39
- - Fix bearer token authentication (1a1ca93)
55
+ * Fix bearer token authentication (1a1ca93)
40
56
 
41
57
  ## [0.5.0] - 2023-08-10
42
58
 
43
- - Add configurable write timeout (2a31f84)
44
- - Use built-in Gem::Version class (066e0b6)
59
+ * Add configurable write timeout (2a31f84)
60
+ * Use built-in Gem::Version class (066e0b6)
45
61
 
46
62
  ## [0.4.0] - 2023-08-06
47
63
 
48
- - Refactor Client into Authenticator, RequestBuilder, Connection, ResponseHandler (6bee1e9)
49
- - Add configurable open timeout (1000f9d)
50
- - 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)
51
67
 
52
68
  ## [0.3.0] - 2023-08-04
53
69
 
54
- - Add accessors to X::Client (e61fa73)
55
- - Add configurable read timeout (41502b9)
56
- - Handle network-related errors (9ed1fb4)
57
- - 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)
58
74
 
59
75
  ## [0.2.0] - 2023-08-02
60
76
 
61
- - Allow configuration of base URL (4bc0531)
62
- - Improve error handling (14dc0cd)
77
+ * Allow configuration of base URL (4bc0531)
78
+ * Improve error handling (14dc0cd)
63
79
 
64
80
  ## [0.1.0] - 2023-08-02
65
81
 
66
- - 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,84 +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=
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=
22
26
 
23
27
  def initialize(bearer_token: nil,
24
28
  api_key: nil, api_key_secret: nil, access_token: nil, access_token_secret: nil,
25
- base_url: Connection::DEFAULT_BASE_URL,
29
+ base_url: DEFAULT_BASE_URL,
26
30
  open_timeout: Connection::DEFAULT_OPEN_TIMEOUT,
27
31
  read_timeout: Connection::DEFAULT_READ_TIMEOUT,
28
32
  write_timeout: Connection::DEFAULT_WRITE_TIMEOUT,
29
33
  proxy_url: nil,
30
- content_type: RequestBuilder::DEFAULT_CONTENT_TYPE,
31
- user_agent: RequestBuilder::DEFAULT_USER_AGENT,
32
34
  debug_output: nil,
33
- array_class: ResponseHandler::DEFAULT_ARRAY_CLASS,
34
- object_class: ResponseHandler::DEFAULT_OBJECT_CLASS,
35
+ array_class: nil,
36
+ object_class: nil,
35
37
  max_redirects: RedirectHandler::DEFAULT_MAX_REDIRECTS)
36
38
 
39
+ @base_url = base_url
37
40
  initialize_authenticator(bearer_token, api_key, api_key_secret, access_token, access_token_secret)
38
- @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,
39
42
  write_timeout: write_timeout, debug_output: debug_output, proxy_url: proxy_url)
40
- @request_builder = RequestBuilder.new(content_type: content_type, user_agent: user_agent)
41
- @redirect_handler = RedirectHandler.new(@authenticator, @connection, @request_builder,
42
- max_redirects: max_redirects)
43
- @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)
44
47
  end
45
48
 
46
- def get(endpoint)
47
- send_request(:get, endpoint)
49
+ def get(endpoint, headers: {})
50
+ execute_request(:get, endpoint, headers: headers)
48
51
  end
49
52
 
50
- def post(endpoint, body = nil)
51
- send_request(:post, endpoint, body)
53
+ def post(endpoint, body = nil, headers: {})
54
+ execute_request(:post, endpoint, body: body, headers: headers)
52
55
  end
53
56
 
54
- def put(endpoint, body = nil)
55
- send_request(:put, endpoint, body)
57
+ def put(endpoint, body = nil, headers: {})
58
+ execute_request(:put, endpoint, body: body, headers: headers)
56
59
  end
57
60
 
58
- def delete(endpoint)
59
- send_request(:delete, endpoint)
61
+ def delete(endpoint, headers: {})
62
+ execute_request(:delete, endpoint, headers: headers)
60
63
  end
61
64
 
62
65
  private
63
66
 
64
67
  def initialize_authenticator(bearer_token, api_key, api_key_secret, access_token, access_token_secret)
65
68
  @authenticator = if bearer_token
66
- BearerTokenAuthenticator.new(bearer_token)
69
+ BearerTokenAuthenticator.new(bearer_token: bearer_token)
67
70
  elsif api_key && api_key_secret && access_token && access_token_secret
68
- 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)
69
73
  else
70
- raise ArgumentError,
71
- "Client must be initialized with either a bearer_token or " \
72
- "an api_key, api_key_secret, access_token, and access_token_secret"
74
+ Authenticator.new
73
75
  end
74
76
  end
75
77
 
76
- def send_request(http_method, endpoint, body = nil)
77
- uri = URI.join(base_uri.to_s, endpoint)
78
- request = @request_builder.build(@authenticator, http_method, uri, body: body)
79
- response = @connection.send_request(request)
80
- final_response = @redirect_handler.handle_redirects(response, request, base_uri)
81
- @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)
82
85
  end
83
86
  end
84
87
  end
data/lib/x/connection.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "forwardable"
2
2
  require "net/http"
3
+ require "openssl"
3
4
  require "uri"
4
5
  require_relative "errors/network_error"
5
6
 
@@ -8,96 +9,72 @@ module X
8
9
  class Connection
9
10
  extend Forwardable
10
11
 
11
- DEFAULT_BASE_URL = "https://api.twitter.com/2/".freeze
12
- DEFAULT_HOST = "https://api.twitter.com".freeze
12
+ DEFAULT_HOST = "api.twitter.com".freeze
13
13
  DEFAULT_PORT = 443
14
14
  DEFAULT_OPEN_TIMEOUT = 60 # seconds
15
15
  DEFAULT_READ_TIMEOUT = 60 # seconds
16
16
  DEFAULT_WRITE_TIMEOUT = 60 # seconds
17
+ DEFAULT_DEBUG_OUTPUT = File.open(File::NULL, "w")
17
18
  NETWORK_ERRORS = [
18
19
  Errno::ECONNREFUSED,
20
+ Errno::ECONNRESET,
19
21
  Net::OpenTimeout,
20
- Net::ReadTimeout
22
+ Net::ReadTimeout,
23
+ OpenSSL::SSL::SSLError
21
24
  ].freeze
22
25
 
23
- attr_reader :base_uri, :proxy_uri, :http_client
26
+ attr_accessor :open_timeout, :read_timeout, :write_timeout, :debug_output
27
+ attr_reader :proxy_url, :proxy_uri
24
28
 
25
- def_delegators :@http_client, :open_timeout, :read_timeout, :write_timeout
26
- def_delegators :@http_client, :open_timeout=, :read_timeout=, :write_timeout=
27
- def_delegator :@http_client, :set_debug_output, :debug_output=
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
28
33
 
29
- def initialize(base_url: DEFAULT_BASE_URL, open_timeout: DEFAULT_OPEN_TIMEOUT,
30
- read_timeout: DEFAULT_READ_TIMEOUT, write_timeout: DEFAULT_WRITE_TIMEOUT, proxy_url: nil, debug_output: nil)
31
- @proxy_uri = URI(proxy_url) unless proxy_url.nil?
32
- self.base_uri = base_url
33
- apply_http_client_settings(
34
- open_timeout: open_timeout,
35
- read_timeout: read_timeout,
36
- write_timeout: write_timeout,
37
- debug_output: debug_output
38
- )
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?
39
41
  end
40
42
 
41
- def send_request(request)
42
- @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)
43
49
  rescue *NETWORK_ERRORS => e
44
- raise NetworkError, "Network error: #{e.message}"
50
+ raise NetworkError, "Network error: #{e}"
45
51
  end
46
52
 
47
- def base_uri=(base_url)
48
- base_uri = URI(base_url)
49
- raise ArgumentError, "Invalid base URL" unless base_uri.is_a?(URI::HTTPS) || base_uri.is_a?(URI::HTTP)
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)
50
57
 
51
- @base_uri = base_uri
52
- update_http_client_settings
53
- end
54
-
55
- def debug_output
56
- @http_client.instance_variable_get(:@debug_output)
58
+ @proxy_uri = proxy_uri
57
59
  end
58
60
 
59
61
  private
60
62
 
61
- def apply_http_client_settings(open_timeout:, read_timeout:, write_timeout:, debug_output:)
62
- @http_client.open_timeout = open_timeout
63
- @http_client.read_timeout = read_timeout
64
- @http_client.write_timeout = write_timeout
65
- @http_client.set_debug_output(debug_output) if debug_output
66
- end
67
-
68
- def current_http_client_settings
69
- {
70
- open_timeout: @http_client.open_timeout,
71
- read_timeout: @http_client.read_timeout,
72
- write_timeout: @http_client.write_timeout,
73
- debug_output: debug_output
74
- }
75
- end
76
-
77
- def update_http_client_settings
78
- conditionally_apply_http_client_settings do
79
- host = @base_uri.host || DEFAULT_HOST
80
- port = @base_uri.port || DEFAULT_PORT
81
- @http_client = build_http_client(host: host, port: port)
82
- @http_client.use_ssl = @base_uri.scheme == "https"
83
- end
84
- end
85
-
86
- def build_http_client(host:, port:)
87
- if @proxy_uri.nil?
88
- Net::HTTP.new(host, port)
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)
89
66
  else
90
- Net::HTTP.new(host, port, @proxy_uri&.host, @proxy_uri&.port, @proxy_uri&.user, @proxy_uri&.password)
67
+ Net::HTTP.new(host, port)
91
68
  end
69
+ configure_http_client(http_client)
92
70
  end
93
71
 
94
- def conditionally_apply_http_client_settings
95
- if @http_client
96
- settings = current_http_client_settings
97
- yield
98
- apply_http_client_settings(**settings)
99
- else
100
- 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)
101
78
  end
102
79
  end
103
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,15 +1,7 @@
1
- require "json"
2
- require "net/http"
3
-
4
1
  module X
5
2
  # Base error class
6
3
  class Error < ::StandardError
7
- JSON_CONTENT_TYPE_REGEXP = %r{application/(problem\+|)json}
8
-
9
- attr_reader :object
10
-
11
- def initialize(msg, response:)
12
- @object = JSON.parse(response.body || "{}") if JSON_CONTENT_TYPE_REGEXP.match?(response["content-type"])
4
+ def initialize(msg, _response = nil)
13
5
  super(msg)
14
6
  end
15
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
@@ -0,0 +1,5 @@
1
+ require_relative "server_error"
2
+
3
+ module X
4
+ class InternalServerError < ServerError; end
5
+ end
@@ -1,5 +1,5 @@
1
1
  require_relative "error"
2
2
 
3
3
  module X
4
- class NetworkError < StandardError; end
4
+ class NetworkError < Error; end
5
5
  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