billingrails 0.1.6 → 0.1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f0eda2df91ec2654e98f944817eb5325bf9c597685c27f7f20f56433075f454
4
- data.tar.gz: e2d82ca82c7ec47bd6118fa35d74725b36ea5cc431e4c1a948fa2621edd46b2b
3
+ metadata.gz: 6e7060b0d621a12ffd9d32d45ae3ae37008c7ccb639aeaa01c17fd3ed8d9db97
4
+ data.tar.gz: a3f901c1ddd2c84196041fbf5394d2e467ed188c052fef3323df1de42d3e3880
5
5
  SHA512:
6
- metadata.gz: 77ac91beb1982d7f043deb7a483f34e2ee8b6eccb0e8323d42c84615fba60c683e7b285877da18be3c720d159f4d9abf15116ff7034f049aef40a6d21b660b66
7
- data.tar.gz: 1284de3a16a9ff9b09f135fe0569846dbe3431efa4f556132eb73c1b003ca34c5ae643ddd1c1b1f0efbda5262acb2e4eadbaf66af4b21c0cf471825521b83e26
6
+ metadata.gz: c36ce4151f805a5e5b1e4b932996fd0b9c583787f3f3082fb607919cd1aaf02227cf21bb4ceaa29f7af7209ca732e7eb6b765470af6f207a83c497bd09ba00ad
7
+ data.tar.gz: 11334c3a58ab78315561ae71cdcd5509a53f9fb1d9b6416fab058b87f53616784acd6935eb1c3dec42f1deea4aadecc362befc72e0dd2a7b07462b8d04eb3ae4
@@ -9,8 +9,11 @@ module Billingrails
9
9
  class Client
10
10
  DEFAULT_BASE_URL = 'https://api.billingrails.com/v1'
11
11
  DEFAULT_TIMEOUT = 30
12
+ DEFAULT_MAX_RETRIES = 3
12
13
 
13
- attr_reader :api_key, :base_url, :timeout
14
+ RETRYABLE_HTTP_STATUSES = [429, 500, 502, 503, 504].freeze
15
+
16
+ attr_reader :api_key, :base_url, :timeout, :max_retries
14
17
  attr_reader :accounts, :invoices, :payments, :payment_links
15
18
  attr_reader :events, :meters, :plans, :fees, :prices, :subscriptions
16
19
  attr_reader :discounts, :credit_grants
@@ -20,10 +23,12 @@ module Billingrails
20
23
  # @param api_key [String] Your API key
21
24
  # @param base_url [String] Base URL for API requests
22
25
  # @param timeout [Integer] Request timeout in seconds
23
- def initialize(api_key:, base_url: DEFAULT_BASE_URL, timeout: DEFAULT_TIMEOUT)
26
+ # @param max_retries [Integer] Max attempts per call for retryable HTTP statuses (see RETRYABLE_HTTP_STATUSES); connection errors are not retried. Default 3.
27
+ def initialize(api_key:, base_url: DEFAULT_BASE_URL, timeout: DEFAULT_TIMEOUT, max_retries: DEFAULT_MAX_RETRIES)
24
28
  @api_key = api_key
25
29
  @base_url = base_url.chomp('/')
26
30
  @timeout = timeout
31
+ @max_retries = max_retries
27
32
  validate_config!
28
33
 
29
34
  # Initialize top-level resources
@@ -35,7 +40,6 @@ module Billingrails
35
40
 
36
41
  @subscriptions = Resources::Subscriptions.new(self)
37
42
  @products = Resources::Products.new(self)
38
- @fees = Resources::Fees.new(self)
39
43
  @prices = Resources::Prices.new(self)
40
44
  @plans = Resources::Plans.new(self)
41
45
  @events = Resources::Events.new(self)
@@ -55,10 +59,43 @@ module Billingrails
55
59
  # @return [Hash] Parsed response body
56
60
  def request(method, path, body: nil, params: nil)
57
61
  uri = build_uri(path, params)
58
- request = build_request(method, uri, body)
59
-
60
- response = execute_request(uri, request)
61
- handle_response(response)
62
+ http_request = build_request(method, uri, body)
63
+
64
+ last_exception = nil
65
+ last_error_response = nil
66
+
67
+ @max_retries.times do |attempt|
68
+ begin
69
+ response = execute_request(uri, http_request)
70
+ rescue StandardError => e
71
+ last_exception = e
72
+ break
73
+ end
74
+
75
+ last_exception = nil
76
+ code = response.code.to_i
77
+
78
+ if (200..299).cover?(code)
79
+ return {} if response.body.nil? || response.body.empty?
80
+ return JSON.parse(response.body)
81
+ end
82
+
83
+ if attempt < @max_retries - 1 && retryable_status?(code)
84
+ sleep(2**attempt)
85
+ next
86
+ end
87
+
88
+ last_error_response = response
89
+ break
90
+ end
91
+
92
+ if last_error_response
93
+ handle_response(last_error_response)
94
+ elsif last_exception
95
+ raise ConnectionError, "Failed to connect to API: #{last_exception.message}"
96
+ else
97
+ raise ConnectionError, 'Failed to connect to API'
98
+ end
62
99
  end
63
100
 
64
101
  private
@@ -67,6 +104,10 @@ module Billingrails
67
104
  raise ArgumentError, 'api_key is required' if @api_key.nil? || @api_key.empty?
68
105
  end
69
106
 
107
+ def retryable_status?(code)
108
+ RETRYABLE_HTTP_STATUSES.include?(code)
109
+ end
110
+
70
111
  def build_uri(path, params)
71
112
  uri = URI.parse("#{@base_url}#{path}")
72
113
  if params && !params.empty?
@@ -104,11 +145,7 @@ module Billingrails
104
145
  http.read_timeout = @timeout
105
146
  http.open_timeout = @timeout
106
147
 
107
- begin
108
- http.request(request)
109
- rescue StandardError => e
110
- raise ConnectionError, "Failed to connect to API: #{e.message}"
111
- end
148
+ http.request(request)
112
149
  end
113
150
 
114
151
  def handle_response(response)
@@ -134,13 +171,15 @@ module Billingrails
134
171
  def handle_error_response(response, error_class)
135
172
  error_data = JSON.parse(response.body) rescue {}
136
173
  message = error_data['message'] || response.message
137
-
174
+ nested = error_data['error']
175
+ nested = {} unless nested.is_a?(Hash)
176
+
138
177
  raise error_class.new(
139
178
  message,
140
179
  status: response.code.to_i,
141
- code: error_data['error']['code'],
142
- type: error_data['error']['type'],
143
- details: error_data['error']['details']
180
+ code: nested['code'],
181
+ type: nested['type'],
182
+ details: nested['details']
144
183
  )
145
184
  end
146
185
  end
@@ -11,6 +11,17 @@ module Billingrails
11
11
  @client = client
12
12
  end
13
13
 
14
+ # List prices
15
+ #
16
+ # Retrieves a paginated list of prices.
17
+ #
18
+ # @param params [Hash, nil] Query parameters
19
+ # @return [Hash] Response data
20
+ def list(params: nil)
21
+ path = "/prices"
22
+ @client.request(:get, path, params: params)
23
+ end
24
+
14
25
  # Create a price
15
26
  #
16
27
  # Creates a price.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Billingrails
4
- VERSION = '0.1.6'
4
+ VERSION = '0.1.7'
5
5
  end
data/lib/billingrails.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # This file is auto-generated. Do not edit manually.
4
-
5
3
  require_relative 'billingrails/version'
6
4
  require_relative 'billingrails/errors'
7
5
  require_relative 'billingrails/client'
@@ -9,7 +7,6 @@ require_relative 'billingrails/client'
9
7
  require_relative 'billingrails/resources/accounts'
10
8
  require_relative 'billingrails/resources/checkout_sessions'
11
9
  require_relative 'billingrails/resources/events'
12
- require_relative 'billingrails/resources/fees'
13
10
  require_relative 'billingrails/resources/plans'
14
11
  require_relative 'billingrails/resources/meters'
15
12
  require_relative 'billingrails/resources/products'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: billingrails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Billingrails
@@ -84,7 +84,6 @@ files:
84
84
  - lib/billingrails/resources/credit_grants.rb
85
85
  - lib/billingrails/resources/discounts.rb
86
86
  - lib/billingrails/resources/events.rb
87
- - lib/billingrails/resources/fees.rb
88
87
  - lib/billingrails/resources/invoices.rb
89
88
  - lib/billingrails/resources/meters.rb
90
89
  - lib/billingrails/resources/payment_links.rb
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This file is auto-generated. Do not edit manually.
4
-
5
- module Billingrails
6
- module Resources
7
- # Fees resource
8
- class Fees
9
- # @param client [Client] The API client
10
- def initialize(client)
11
- @client = client
12
- end
13
-
14
- # List fees
15
- #
16
- # Retrieve a list of fees.
17
- #
18
- # @return [Hash] Response data
19
- def list()
20
- path = "/fees"
21
- @client.request(:get, path)
22
- end
23
-
24
- # Create a fee
25
- #
26
- # Creates a fee.
27
- #
28
- # @param data [Hash] Request body
29
- # @return [Hash] Response data
30
- def create(data)
31
- path = "/fees"
32
- @client.request(:post, path, body: data)
33
- end
34
-
35
- # Retrieve fee
36
- #
37
- # Retrieves a fee by ID.
38
- #
39
- # @param id [String] Resource ID
40
- # @param params [Hash, nil] Query parameters
41
- # @return [Hash] Response data
42
- def retrieve(id, params: nil)
43
- path = "/fees/#{id}"
44
- @client.request(:get, path, params: params)
45
- end
46
-
47
- # Update a fee
48
- #
49
- # Updates a fee.
50
- #
51
- # @param id [String] Resource ID
52
- # @param data [Hash] Request body
53
- # @return [Hash] Response data
54
- def update(id, data)
55
- path = "/fees/#{id}"
56
- @client.request(:put, path, body: data)
57
- end
58
-
59
- # Delete a fee
60
- #
61
- # Deletes a fee.
62
- #
63
- # @param id [String] Resource ID
64
- # @return [Hash] Response data
65
- def delete(id)
66
- path = "/fees/#{id}"
67
- @client.request(:delete, path)
68
- end
69
-
70
- # Archive a fee
71
- #
72
- # Archives a fee.
73
- #
74
- # @param id [String] Resource ID
75
- # @return [Hash] Response data
76
- def archive(id)
77
- path = "/fees/#{id}/archive"
78
- @client.request(:post, path)
79
- end
80
-
81
- # Unarchive a fee
82
- #
83
- # Restores an archived fee.
84
- #
85
- # @param id [String] Resource ID
86
- # @return [Hash] Response data
87
- def unarchive(id)
88
- path = "/fees/#{id}/unarchive"
89
- @client.request(:post, path)
90
- end
91
-
92
- end
93
- end
94
- end