pco_api 1.3.0 → 2.0.1

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: cb681a310a78eeb3ac455edc7ab2b4696a246e74a54077b1f0c5ce26e9a31c10
4
- data.tar.gz: fe3398a9fd3c50f784e139fd65879a31cdf56d210a97e3e46e5f66309058b0f6
3
+ metadata.gz: 80591277ecc37d298f7a7c68c35d32cd9f5d117f401ee6c811a417aab5b9e494
4
+ data.tar.gz: 756f395bb87741e0786452d1391a47c08bc3a36df064f8fa6d368706e49128de
5
5
  SHA512:
6
- metadata.gz: 41d1955114ffe087506d63c3907ebad24f9c0a34e9e3784d620bc2be8080bf309b3eb0fbed52a60b5805e1e2cf0ccfe07d6adcc0072a48f78336461d9e7ca14b
7
- data.tar.gz: 1ead2832a8c2f62c13845b5c7c28254494efdbdedf404b6e70ccbd9791fd12ee9932acfad3ed9255dc9d3451eaf4dd4841cb2a1ed99721304a15fc5260c1301d
6
+ metadata.gz: a64b77f5502cb0e7a83b3841596002402ed6484738185f0397d4bd9fccd451c3b3494e95a7e9c13a22f9123e20509c484b77528db19a2b972e8bfc61db43ff3d
7
+ data.tar.gz: a7c05f672220939fc491e20e334ba5511173ac4ed50e3bf3969530d7f1556cd7ed8147b0172dc1d727ed9696e134c32ab4a7cb3564585cfd96abea2743a8ff26
data/README.md CHANGED
@@ -210,6 +210,7 @@ The following errors may be raised by the library, depending on the API response
210
210
  | 404 | `PCO::API::Errors::NotFound` < `PCO::API::Errors::ClientError` |
211
211
  | 405 | `PCO::API::Errors::MethodNotAllowed` < `PCO::API::Errors::ClientError` |
212
212
  | 422 | `PCO::API::Errors::UnprocessableEntity` < `PCO::API::Errors::ClientError` |
213
+ | 429 | `PCO::API::Errors::TooManyRequests` < `PCO::API::Errors::ClientError` |
213
214
  | other 4xx errors | `PCO::API::Errors::ClientError` |
214
215
  | 500 | `PCO::API::Errors::InternalServerError` < `PCO::API::Errors::ServerError` |
215
216
  | other 5xx errors | `PCO::API::Errors::ServerError` |
@@ -221,6 +222,7 @@ The exception object has the following methods:
221
222
  | status | HTTP status code returned by the server |
222
223
  | message | the message returned by the API |
223
224
  | detail | the full error response returned by the API |
225
+ | headers | hash of HTTP headers returned by the API |
224
226
 
225
227
  The `message` should be a simple string given by the API, e.g. "Resource Not Found".
226
228
 
@@ -229,6 +231,17 @@ In the case of validation errors, the `message` is a summary string built from t
229
231
  Alternatively, you may rescue `PCO::API::Errors::BaseError` and branch your code based on
230
232
  the status code returned by calling `error.status`.
231
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
+
232
245
  ## Copyright & License
233
246
 
234
247
  Copyright Ministry Centered Technologies. Licensed MIT.
@@ -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
@@ -126,15 +137,25 @@ module PCO
126
137
  Faraday.new(url: url) do |faraday|
127
138
  faraday.response :json, content_type: /\bjson$/
128
139
  if @basic_auth_token && @basic_auth_secret
129
- faraday.basic_auth @basic_auth_token, @basic_auth_secret
140
+ faraday.request :basic_auth, @basic_auth_token, @basic_auth_secret
130
141
  elsif @oauth_access_token
131
- faraday.headers['Authorization'] = "Bearer #{@oauth_access_token}"
142
+ faraday.request :authorization, 'Bearer', @oauth_access_token
132
143
  else
133
144
  fail Errors::AuthRequiredError, "You must specify either HTTP basic auth credentials or an OAuth2 access token."
134
145
  end
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
- end
161
+ end
@@ -1,5 +1,5 @@
1
1
  module PCO
2
2
  module API
3
- VERSION = '1.3.0'
3
+ VERSION = '2.0.1'
4
4
  end
5
5
  end
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
@@ -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
@@ -0,0 +1,9 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe PCO::API do
4
+ describe '.new' do
5
+ it 'creates a new Endpoint instance' do
6
+ expect(described_class.new(basic_auth_token: 'abc123', basic_auth_secret: 'xyz789').class).to eq(PCO::API::Endpoint)
7
+ end
8
+ end
9
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pco_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Planning Center Online
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-21 00:00:00.000000000 Z
11
+ date: 2022-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.10'
19
+ version: '1.8'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.10'
26
+ version: '1.8'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: faraday_middleware
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.10'
33
+ version: '1.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.10'
40
+ version: '1.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: excon
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -109,12 +109,13 @@ files:
109
109
  - lib/pco/api/version.rb
110
110
  - lib/pco_api.rb
111
111
  - spec/pco/api/endpoint_spec.rb
112
+ - spec/pco/api_spec.rb
112
113
  - spec/spec_helper.rb
113
114
  homepage: https://github.com/planningcenter/pco_api_ruby
114
115
  licenses:
115
116
  - MIT
116
117
  metadata: {}
117
- post_install_message:
118
+ post_install_message:
118
119
  rdoc_options: []
119
120
  require_paths:
120
121
  - lib
@@ -129,10 +130,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
130
  - !ruby/object:Gem::Version
130
131
  version: '0'
131
132
  requirements: []
132
- rubygems_version: 3.0.3
133
- signing_key:
133
+ rubygems_version: 3.0.3.1
134
+ signing_key:
134
135
  specification_version: 4
135
136
  summary: API wrapper for api.planningcenteronline.com
136
137
  test_files:
138
+ - spec/pco/api_spec.rb
137
139
  - spec/pco/api/endpoint_spec.rb
138
140
  - spec/spec_helper.rb