pco_api 1.3.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eee1d9d3e7b4407dfc0b5f183021246c34a1467936fb77743c4cd45a1767b9b7
4
- data.tar.gz: 014ec30ad0b2c1b814b10da5ee26716f55cea5bf85a782e4230feaadf7f0c260
3
+ metadata.gz: 6e9b56ec41159e601c1afb0b4fa004797f91d0ae845ba396e09617738f98cdea
4
+ data.tar.gz: 931ed18a093f13ba313d6070b2307d888db9d38fe434308f76e6b0b5b0cf9715
5
5
  SHA512:
6
- metadata.gz: b36cca693f502f4c4b123aa22c61b72d41ccd51457eee7c2aef87454559d1fb7ffe85241ec97ab8832925830f864e773ce22b319d278f474245826f44bfe20e1
7
- data.tar.gz: 3c16320118da5aee58fcec347cae41df8c215d176331863d61d079a0b47bbc23998816ff09dbecbce888177faa7847da2f13f66fe4c984622fb74cb641eb9372
6
+ metadata.gz: 21f690d99a0ea0896ab49a416d64ae802c7f993a6f63afa725b7e6ab098a2049a6d7aad3e1dc7b0f230eb2db4bb2faceba7760d054b0c8595138708438348a66
7
+ data.tar.gz: cc5b2478ae1de0b2911594483573266d9f3447078b81529c97e9765c209d49af7b9c99f80a14a089d6c92d0c7d5be3e33cde7a17a4d25cfc4ad64e0f0d030e37
data/README.md CHANGED
@@ -231,6 +231,17 @@ In the case of validation errors, the `message` is a summary string built from t
231
231
  Alternatively, you may rescue `PCO::API::Errors::BaseError` and branch your code based on
232
232
  the status code returned by calling `error.status`.
233
233
 
234
+ ### TooManyRequests Error
235
+
236
+ By default, PCO::API::Endpoint will sleep and retry a request that fails with TooManyRequests due
237
+ to rate limiting. If you would rather catch and handle such errors yourself, you can disable this
238
+ behavior like this:
239
+
240
+ ```ruby
241
+ api = PCO::API.new(...)
242
+ api.retry_when_rate_limited = false
243
+ ```
244
+
234
245
  ## Copyright & License
235
246
 
236
247
  Copyright Ministry Centered Technologies. Licensed MIT.
data/lib/pco/api.rb CHANGED
@@ -3,9 +3,10 @@ require_relative 'api/errors'
3
3
 
4
4
  module PCO
5
5
  module API
6
- module_function
7
- def new(**args)
8
- Endpoint.new(**args)
6
+ class << self
7
+ def new(**args)
8
+ Endpoint.new(**args)
9
+ end
9
10
  end
10
11
  end
11
12
  end
@@ -12,6 +12,8 @@ module PCO
12
12
  class Endpoint
13
13
  attr_reader :url, :last_result
14
14
 
15
+ attr_accessor :retry_when_rate_limited
16
+
15
17
  def initialize(url: URL, oauth_access_token: nil, basic_auth_token: nil, basic_auth_secret: nil, connection: nil)
16
18
  @url = url
17
19
  @oauth_access_token = oauth_access_token
@@ -19,6 +21,7 @@ module PCO
19
21
  @basic_auth_secret = basic_auth_secret
20
22
  @connection = connection || _build_connection
21
23
  @cache = {}
24
+ @retry_when_rate_limited = true
22
25
  end
23
26
 
24
27
  def method_missing(method_name, *_args)
@@ -29,7 +32,7 @@ module PCO
29
32
  _build_endpoint(id.to_s)
30
33
  end
31
34
 
32
- def respond_to?(method_name)
35
+ def respond_to?(method_name, _include_all = false)
33
36
  endpoint = _build_endpoint(method_name.to_s)
34
37
  begin
35
38
  endpoint.get
@@ -43,6 +46,8 @@ module PCO
43
46
  def get(params = {})
44
47
  @last_result = @connection.get(@url, params)
45
48
  _build_response(@last_result)
49
+ rescue Errors::TooManyRequests => e
50
+ _retry_after_timeout?(e) ? retry : raise
46
51
  end
47
52
 
48
53
  def post(body = {})
@@ -50,6 +55,8 @@ module PCO
50
55
  req.body = _build_body(body)
51
56
  end
52
57
  _build_response(@last_result)
58
+ rescue Errors::TooManyRequests => e
59
+ _retry_after_timeout?(e) ? retry : raise
53
60
  end
54
61
 
55
62
  def patch(body = {})
@@ -57,6 +64,8 @@ module PCO
57
64
  req.body = _build_body(body)
58
65
  end
59
66
  _build_response(@last_result)
67
+ rescue Errors::TooManyRequests => e
68
+ _retry_after_timeout?(e) ? retry : raise
60
69
  end
61
70
 
62
71
  def delete
@@ -66,6 +75,8 @@ module PCO
66
75
  else
67
76
  _build_response(@last_result)
68
77
  end
78
+ rescue Errors::TooManyRequests => e
79
+ _retry_after_timeout?(e) ? retry : raise
69
80
  end
70
81
 
71
82
  private
@@ -135,6 +146,16 @@ module PCO
135
146
  faraday.adapter :excon
136
147
  end
137
148
  end
149
+
150
+ def _retry_after_timeout?(e)
151
+ if @retry_when_rate_limited
152
+ secs = e.headers['Retry-After']
153
+ Kernel.sleep(secs ? secs.to_i : 1)
154
+ true
155
+ else
156
+ false
157
+ end
158
+ end
138
159
  end
139
160
  end
140
161
  end
@@ -1,5 +1,5 @@
1
1
  module PCO
2
2
  module API
3
- VERSION = '1.3.1'
3
+ VERSION = '2.0.0'
4
4
  end
5
5
  end
@@ -124,6 +124,48 @@ describe PCO::API::Endpoint do
124
124
  }.to raise_error(PCO::API::Errors::ServerError)
125
125
  end
126
126
  end
127
+
128
+ context 'given a 429 error due to rate limiting' do
129
+ subject { base.people.v2 }
130
+
131
+ let(:result) do
132
+ {
133
+ 'type' => 'Organization',
134
+ 'id' => '1',
135
+ 'name' => 'Ministry Centered Technologies',
136
+ 'links' => {}
137
+ }
138
+ end
139
+
140
+ before do
141
+ stub_request(:get, 'https://api.planningcenteronline.com/people/v2')
142
+ .to_return([
143
+ { status: 429, headers: { 'retry-after' => '2' } },
144
+ { status: 200, body: { data: result }.to_json, headers: { 'Content-Type' => 'application/vnd.api+json' } }
145
+ ])
146
+ end
147
+
148
+ context 'given retry_when_rate_limited is true' do
149
+ before do
150
+ subject.retry_when_rate_limited = true
151
+ end
152
+
153
+ it 'sleeps, then makes the call again' do
154
+ expect(Kernel).to receive(:sleep).with(2)
155
+ expect(subject.get).to be_a(Hash)
156
+ end
157
+ end
158
+
159
+ context 'given retry_when_rate_limited is false' do
160
+ before do
161
+ subject.retry_when_rate_limited = false
162
+ end
163
+
164
+ it 'raises the TooManyRequests error' do
165
+ expect { subject.get }.to raise_error(PCO::API::Errors::TooManyRequests)
166
+ end
167
+ end
168
+ end
127
169
  end
128
170
 
129
171
  describe '#post' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pco_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Planning Center Online