wcc-contentful 0.3.0 → 1.0.0.pre.rc2
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 +5 -5
- data/.rspec +1 -1
- data/Guardfile +43 -0
- data/README.md +161 -11
- data/Rakefile +3 -6
- data/app/controllers/wcc/contentful/webhook_controller.rb +25 -24
- data/app/jobs/wcc/contentful/webhook_enable_job.rb +36 -2
- data/bin/console +4 -3
- data/bin/rails +2 -0
- data/config/routes.rb +1 -1
- data/doc +1 -0
- data/lib/tasks/download_schema.rake +12 -0
- data/lib/wcc/contentful.rb +69 -45
- data/lib/wcc/contentful/active_record_shim.rb +72 -0
- data/lib/wcc/contentful/configuration.rb +177 -46
- data/lib/wcc/contentful/content_type_indexer.rb +14 -0
- data/lib/wcc/contentful/downloads_schema.rb +112 -0
- data/lib/wcc/contentful/engine.rb +33 -14
- data/lib/wcc/contentful/event.rb +171 -0
- data/lib/wcc/contentful/events.rb +41 -0
- data/lib/wcc/contentful/exceptions.rb +3 -33
- data/lib/wcc/contentful/indexed_representation.rb +2 -2
- data/lib/wcc/contentful/instrumentation.rb +31 -0
- data/lib/wcc/contentful/link.rb +28 -0
- data/lib/wcc/contentful/link_visitor.rb +122 -0
- data/lib/wcc/contentful/middleware.rb +7 -0
- data/lib/wcc/contentful/middleware/store.rb +158 -0
- data/lib/wcc/contentful/middleware/store/caching_middleware.rb +114 -0
- data/lib/wcc/contentful/model.rb +37 -4
- data/lib/wcc/contentful/model_builder.rb +1 -0
- data/lib/wcc/contentful/model_methods.rb +40 -15
- data/lib/wcc/contentful/model_singleton_methods.rb +47 -30
- data/lib/wcc/contentful/rake.rb +4 -0
- data/lib/wcc/contentful/rspec.rb +46 -0
- data/lib/wcc/contentful/services.rb +61 -27
- data/lib/wcc/contentful/simple_client.rb +81 -25
- data/lib/wcc/contentful/simple_client/management.rb +43 -10
- data/lib/wcc/contentful/simple_client/response.rb +61 -22
- data/lib/wcc/contentful/simple_client/typhoeus_adapter.rb +17 -17
- data/lib/wcc/contentful/store.rb +7 -66
- data/lib/wcc/contentful/store/README.md +85 -0
- data/lib/wcc/contentful/store/base.rb +34 -119
- data/lib/wcc/contentful/store/cdn_adapter.rb +71 -12
- data/lib/wcc/contentful/store/factory.rb +186 -0
- data/lib/wcc/contentful/store/instrumentation.rb +55 -0
- data/lib/wcc/contentful/store/interface.rb +82 -0
- data/lib/wcc/contentful/store/memory_store.rb +27 -24
- data/lib/wcc/contentful/store/postgres_store.rb +268 -101
- data/lib/wcc/contentful/store/postgres_store/schema_1.sql +73 -0
- data/lib/wcc/contentful/store/postgres_store/schema_2.sql +21 -0
- data/lib/wcc/contentful/store/query.rb +246 -0
- data/lib/wcc/contentful/store/query/interface.rb +63 -0
- data/lib/wcc/contentful/store/rspec_examples.rb +48 -0
- data/lib/wcc/contentful/store/rspec_examples/basic_store.rb +629 -0
- data/lib/wcc/contentful/store/rspec_examples/include_param.rb +283 -0
- data/lib/wcc/contentful/store/rspec_examples/nested_queries.rb +342 -0
- data/lib/wcc/contentful/sync_engine.rb +181 -0
- data/lib/wcc/contentful/test.rb +7 -0
- data/lib/wcc/contentful/test/attributes.rb +56 -0
- data/lib/wcc/contentful/test/double.rb +76 -0
- data/lib/wcc/contentful/test/factory.rb +101 -0
- data/lib/wcc/contentful/version.rb +1 -1
- data/wcc-contentful.gemspec +28 -14
- metadata +248 -152
- data/.circleci/config.yml +0 -51
- data/.gitignore +0 -26
- data/.rubocop.yml +0 -242
- data/.rubocop_todo.yml +0 -19
- data/.travis.yml +0 -5
- data/CHANGELOG.md +0 -180
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -8
- data/LICENSE.txt +0 -21
- data/app/jobs/wcc/contentful/delayed_sync_job.rb +0 -63
- data/lib/generators/wcc/USAGE +0 -24
- data/lib/generators/wcc/model_generator.rb +0 -90
- data/lib/generators/wcc/templates/.keep +0 -0
- data/lib/generators/wcc/templates/Procfile +0 -3
- data/lib/generators/wcc/templates/contentful_shell_wrapper +0 -385
- data/lib/generators/wcc/templates/menu/generated_add_menus.ts +0 -192
- data/lib/generators/wcc/templates/menu/models/menu.rb +0 -23
- data/lib/generators/wcc/templates/menu/models/menu_button.rb +0 -23
- data/lib/generators/wcc/templates/page/generated_add_pages.ts +0 -50
- data/lib/generators/wcc/templates/page/models/page.rb +0 -23
- data/lib/generators/wcc/templates/release +0 -9
- data/lib/generators/wcc/templates/wcc_contentful.rb +0 -17
- data/lib/wcc/contentful/client_ext.rb +0 -28
- data/lib/wcc/contentful/graphql.rb +0 -14
- data/lib/wcc/contentful/graphql/builder.rb +0 -177
- data/lib/wcc/contentful/graphql/types.rb +0 -54
- data/lib/wcc/contentful/model/dropdown_menu.rb +0 -7
- data/lib/wcc/contentful/model/menu.rb +0 -6
- data/lib/wcc/contentful/model/menu_button.rb +0 -16
- data/lib/wcc/contentful/model/page.rb +0 -8
- data/lib/wcc/contentful/model/redirect.rb +0 -19
- data/lib/wcc/contentful/model_validators.rb +0 -121
- data/lib/wcc/contentful/model_validators/dsl.rb +0 -166
- data/lib/wcc/contentful/simple_client/http_adapter.rb +0 -24
- data/lib/wcc/contentful/store/lazy_cache_store.rb +0 -161
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative 'simple_client/response'
|
4
4
|
require_relative 'simple_client/management'
|
5
|
+
require_relative 'instrumentation'
|
5
6
|
|
6
7
|
module WCC::Contentful
|
7
8
|
# The SimpleClient accesses the Contentful CDN to get JSON responses,
|
@@ -16,11 +17,13 @@ module WCC::Contentful
|
|
16
17
|
# `get`. This method returns a WCC::Contentful::SimpleClient::Response
|
17
18
|
# that handles paging automatically.
|
18
19
|
#
|
19
|
-
# The SimpleClient by default uses '
|
20
|
-
# client
|
20
|
+
# The SimpleClient by default uses 'faraday' to perform the gets, but any HTTP
|
21
|
+
# client adapter be injected by passing the `connection:` option.
|
21
22
|
#
|
22
23
|
# @api Client
|
23
24
|
class SimpleClient
|
25
|
+
include WCC::Contentful::Instrumentation
|
26
|
+
|
24
27
|
attr_reader :api_url
|
25
28
|
attr_reader :space
|
26
29
|
|
@@ -30,21 +33,27 @@ module WCC::Contentful
|
|
30
33
|
# @param [String] space The Space ID to access
|
31
34
|
# @param [String] access_token A Contentful Access Token to be sent in the Authorization header
|
32
35
|
# @param [Hash] options The remaining optional parameters, defined below
|
33
|
-
# @option options [Symbol, Object]
|
36
|
+
# @option options [Symbol, Object] connection The Faraday connection to use to make requests.
|
34
37
|
# Auto-discovered based on what gems are installed if this is not provided.
|
35
38
|
# @option options [String] default_locale The locale query param to set by default.
|
36
39
|
# @option options [String] environment The contentful environment to access. Defaults to 'master'.
|
37
40
|
# @option options [Boolean] no_follow_redirects If true, do not follow 300 level redirects.
|
41
|
+
# @option options [Number] rate_limit_wait_timeout The maximum time to block the thread waiting
|
42
|
+
# on a rate limit response. By default will wait for one 429 and then fail on the second 429.
|
38
43
|
def initialize(api_url:, space:, access_token:, **options)
|
39
44
|
@api_url = URI.join(api_url, '/spaces/', space + '/')
|
40
45
|
@space = space
|
41
46
|
@access_token = access_token
|
42
47
|
|
43
|
-
@adapter = SimpleClient.load_adapter(options[:
|
48
|
+
@adapter = SimpleClient.load_adapter(options[:connection])
|
44
49
|
|
45
50
|
@options = options
|
51
|
+
@_instrumentation = @options[:instrumentation]
|
46
52
|
@query_defaults = {}
|
47
53
|
@query_defaults[:locale] = @options[:default_locale] if @options[:default_locale]
|
54
|
+
# default 1.5 so that we retry one time then fail if still rate limited
|
55
|
+
# https://www.contentful.com/developers/docs/references/content-preview-api/#/introduction/api-rate-limits
|
56
|
+
@rate_limit_wait_timeout = @options[:rate_limit_wait_timeout] || 1.5
|
48
57
|
|
49
58
|
return unless options[:environment].present?
|
50
59
|
|
@@ -57,13 +66,17 @@ module WCC::Contentful
|
|
57
66
|
def get(path, query = {})
|
58
67
|
url = URI.join(@api_url, path)
|
59
68
|
|
69
|
+
resp =
|
70
|
+
_instrument 'get_http', url: url, query: query do
|
71
|
+
get_http(url, query)
|
72
|
+
end
|
60
73
|
Response.new(self,
|
61
74
|
{ url: url, query: query },
|
62
|
-
|
75
|
+
resp)
|
63
76
|
end
|
64
77
|
|
65
78
|
ADAPTERS = {
|
66
|
-
|
79
|
+
faraday: ['faraday', '>= 0.9'],
|
67
80
|
typhoeus: ['typhoeus', '~> 1.0']
|
68
81
|
}.freeze
|
69
82
|
|
@@ -80,16 +93,19 @@ module WCC::Contentful
|
|
80
93
|
end
|
81
94
|
raise ArgumentError, 'Unable to load adapter! Please install one of '\
|
82
95
|
"#{ADAPTERS.values.map(&:join).join(',')}"
|
83
|
-
when :
|
84
|
-
|
85
|
-
|
96
|
+
when :faraday
|
97
|
+
require 'faraday'
|
98
|
+
::Faraday.new do |faraday|
|
99
|
+
faraday.response :logger, (Rails.logger if defined?(Rails)), { headers: false, bodies: false }
|
100
|
+
faraday.adapter :net_http
|
101
|
+
end
|
86
102
|
when :typhoeus
|
87
103
|
require_relative 'simple_client/typhoeus_adapter'
|
88
104
|
TyphoeusAdapter.new
|
89
105
|
else
|
90
|
-
unless adapter.respond_to?(:
|
106
|
+
unless adapter.respond_to?(:get)
|
91
107
|
raise ArgumentError, "Adapter #{adapter} is not invokeable! Please "\
|
92
|
-
"pass
|
108
|
+
"pass use one of #{ADAPTERS.keys} or create a Faraday-compatible adapter"
|
93
109
|
end
|
94
110
|
adapter
|
95
111
|
end
|
@@ -97,7 +113,12 @@ module WCC::Contentful
|
|
97
113
|
|
98
114
|
private
|
99
115
|
|
100
|
-
def
|
116
|
+
def _instrumentation_event_prefix
|
117
|
+
# Unify all CDN, Management, Preview notifications under same namespace
|
118
|
+
'.simpleclient.contentful.wcc'
|
119
|
+
end
|
120
|
+
|
121
|
+
def get_http(url, query, headers = {})
|
101
122
|
headers = {
|
102
123
|
Authorization: "Bearer #{@access_token}"
|
103
124
|
}.merge(headers || {})
|
@@ -105,12 +126,28 @@ module WCC::Contentful
|
|
105
126
|
q = @query_defaults.dup
|
106
127
|
q = q.merge(query) if query
|
107
128
|
|
108
|
-
|
129
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
130
|
+
loop do
|
131
|
+
resp = @adapter.get(url, q, headers)
|
132
|
+
|
133
|
+
if [301, 302, 307].include?(resp.status) && !@options[:no_follow_redirects]
|
134
|
+
url = resp.headers['Location']
|
135
|
+
next
|
136
|
+
end
|
137
|
+
|
138
|
+
if resp.status == 429 &&
|
139
|
+
reset = resp.headers['X-Contentful-RateLimit-Reset'].presence
|
140
|
+
reset = reset.to_f
|
141
|
+
_instrument 'rate_limit', start: start, reset: reset, timeout: @rate_limit_wait_timeout
|
142
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
143
|
+
if (now - start) + reset < @rate_limit_wait_timeout
|
144
|
+
sleep(reset)
|
145
|
+
next
|
146
|
+
end
|
147
|
+
end
|
109
148
|
|
110
|
-
|
111
|
-
resp = get_http(resp.headers['location'], nil, headers, proxy)
|
149
|
+
return resp
|
112
150
|
end
|
113
|
-
resp
|
114
151
|
end
|
115
152
|
|
116
153
|
# The CDN SimpleClient accesses 'https://cdn.contentful.com' to get raw
|
@@ -135,31 +172,46 @@ module WCC::Contentful
|
|
135
172
|
|
136
173
|
# Gets an entry by ID
|
137
174
|
def entry(key, query = {})
|
138
|
-
resp =
|
175
|
+
resp =
|
176
|
+
_instrument 'entries', id: key, type: 'Entry', query: query do
|
177
|
+
get("entries/#{key}", query)
|
178
|
+
end
|
139
179
|
resp.assert_ok!
|
140
180
|
end
|
141
181
|
|
142
182
|
# Queries entries with optional query parameters
|
143
183
|
def entries(query = {})
|
144
|
-
resp =
|
184
|
+
resp =
|
185
|
+
_instrument 'entries', type: 'Entry', query: query do
|
186
|
+
get('entries', query)
|
187
|
+
end
|
145
188
|
resp.assert_ok!
|
146
189
|
end
|
147
190
|
|
148
191
|
# Gets an asset by ID
|
149
192
|
def asset(key, query = {})
|
150
|
-
resp =
|
193
|
+
resp =
|
194
|
+
_instrument 'entries', type: 'Asset', id: key, query: query do
|
195
|
+
get("assets/#{key}", query)
|
196
|
+
end
|
151
197
|
resp.assert_ok!
|
152
198
|
end
|
153
199
|
|
154
200
|
# Queries assets with optional query parameters
|
155
201
|
def assets(query = {})
|
156
|
-
resp =
|
202
|
+
resp =
|
203
|
+
_instrument 'entries', type: 'Asset', query: query do
|
204
|
+
get('assets', query)
|
205
|
+
end
|
157
206
|
resp.assert_ok!
|
158
207
|
end
|
159
208
|
|
160
209
|
# Queries content types with optional query parameters
|
161
210
|
def content_types(query = {})
|
162
|
-
resp =
|
211
|
+
resp =
|
212
|
+
_instrument 'content_types', query: query do
|
213
|
+
get('content_types', query)
|
214
|
+
end
|
163
215
|
resp.assert_ok!
|
164
216
|
end
|
165
217
|
|
@@ -177,7 +229,11 @@ module WCC::Contentful
|
|
177
229
|
{ initial: true }
|
178
230
|
end
|
179
231
|
query = query.merge(sync_token)
|
180
|
-
resp =
|
232
|
+
resp =
|
233
|
+
_instrument 'sync', sync_token: sync_token, query: query do
|
234
|
+
get('sync', query)
|
235
|
+
end
|
236
|
+
resp = SyncResponse.new(resp)
|
181
237
|
resp.assert_ok!
|
182
238
|
end
|
183
239
|
end
|
@@ -186,10 +242,10 @@ module WCC::Contentful
|
|
186
242
|
class Preview < Cdn
|
187
243
|
def initialize(space:, preview_token:, **options)
|
188
244
|
super(
|
189
|
-
|
245
|
+
**options,
|
246
|
+
api_url: options[:preview_api_url] || 'https://preview.contentful.com/',
|
190
247
|
space: space,
|
191
|
-
access_token: preview_token
|
192
|
-
**options
|
248
|
+
access_token: preview_token
|
193
249
|
)
|
194
250
|
end
|
195
251
|
|
@@ -4,10 +4,10 @@
|
|
4
4
|
class WCC::Contentful::SimpleClient::Management < WCC::Contentful::SimpleClient
|
5
5
|
def initialize(space:, management_token:, **options)
|
6
6
|
super(
|
7
|
-
|
7
|
+
**options,
|
8
|
+
api_url: options[:management_api_url] || 'https://api.contentful.com',
|
8
9
|
space: space,
|
9
10
|
access_token: management_token,
|
10
|
-
**options
|
11
11
|
)
|
12
12
|
|
13
13
|
@post_adapter = @adapter if @adapter.respond_to?(:post)
|
@@ -19,12 +19,34 @@ class WCC::Contentful::SimpleClient::Management < WCC::Contentful::SimpleClient
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def content_types(**query)
|
22
|
-
resp =
|
22
|
+
resp =
|
23
|
+
_instrument 'content_types', query: query do
|
24
|
+
get('content_types', query)
|
25
|
+
end
|
26
|
+
resp.assert_ok!
|
27
|
+
end
|
28
|
+
|
29
|
+
def content_type(key, query = {})
|
30
|
+
resp =
|
31
|
+
_instrument 'content_types', content_type: key, query: query do
|
32
|
+
get("content_types/#{key}", query)
|
33
|
+
end
|
34
|
+
resp.assert_ok!
|
35
|
+
end
|
36
|
+
|
37
|
+
def editor_interface(content_type_id, query = {})
|
38
|
+
resp =
|
39
|
+
_instrument 'editor_interfaces', content_type: content_type_id, query: query do
|
40
|
+
get("content_types/#{content_type_id}/editor_interface", query)
|
41
|
+
end
|
23
42
|
resp.assert_ok!
|
24
43
|
end
|
25
44
|
|
26
45
|
def webhook_definitions(**query)
|
27
|
-
resp =
|
46
|
+
resp =
|
47
|
+
_instrument 'webhook_definitions', query: query do
|
48
|
+
get("/spaces/#{space}/webhook_definitions", query)
|
49
|
+
end
|
28
50
|
resp.assert_ok!
|
29
51
|
end
|
30
52
|
|
@@ -51,30 +73,41 @@ class WCC::Contentful::SimpleClient::Management < WCC::Contentful::SimpleClient
|
|
51
73
|
# ]
|
52
74
|
# }
|
53
75
|
def post_webhook_definition(webhook)
|
54
|
-
resp =
|
76
|
+
resp =
|
77
|
+
_instrument 'post.webhook_definitions' do
|
78
|
+
post("/spaces/#{space}/webhook_definitions", webhook)
|
79
|
+
end
|
55
80
|
resp.assert_ok!
|
56
81
|
end
|
57
82
|
|
58
83
|
def post(path, body)
|
59
84
|
url = URI.join(@api_url, path)
|
60
85
|
|
86
|
+
resp =
|
87
|
+
_instrument 'post_http', url: url do
|
88
|
+
post_http(url, body)
|
89
|
+
end
|
90
|
+
|
61
91
|
Response.new(self,
|
62
92
|
{ url: url, body: body },
|
63
|
-
|
93
|
+
resp)
|
64
94
|
end
|
65
95
|
|
66
96
|
private
|
67
97
|
|
68
|
-
def post_http(url, body, headers = {}
|
98
|
+
def post_http(url, body, headers = {})
|
69
99
|
headers = {
|
70
100
|
Authorization: "Bearer #{@access_token}",
|
71
101
|
'Content-Type' => 'application/vnd.contentful.management.v1+json'
|
72
102
|
}.merge(headers || {})
|
73
103
|
|
74
|
-
|
104
|
+
body = body.to_json unless body.is_a? String
|
105
|
+
resp = @post_adapter.post(url, body, headers)
|
75
106
|
|
76
|
-
if [301, 302, 307].include?(resp.
|
77
|
-
resp = get_http(resp.headers['location'], nil, headers
|
107
|
+
if [301, 302, 307].include?(resp.status) && !@options[:no_follow_redirects]
|
108
|
+
resp = get_http(resp.headers['location'], nil, headers)
|
109
|
+
elsif resp.status == 308 && !@options[:no_follow_redirects]
|
110
|
+
resp = post_http(resp.headers['location'], body, headers)
|
78
111
|
end
|
79
112
|
resp
|
80
113
|
end
|
@@ -1,12 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../instrumentation'
|
4
|
+
|
3
5
|
class WCC::Contentful::SimpleClient
|
4
6
|
class Response
|
7
|
+
include ::WCC::Contentful::Instrumentation
|
8
|
+
|
5
9
|
attr_reader :raw_response
|
6
10
|
attr_reader :client
|
7
11
|
attr_reader :request
|
8
12
|
|
9
|
-
delegate :
|
13
|
+
delegate :status, to: :raw_response
|
14
|
+
alias_method :code, :status
|
10
15
|
delegate :headers, to: :raw_response
|
11
16
|
|
12
17
|
def body
|
@@ -19,25 +24,41 @@ class WCC::Contentful::SimpleClient
|
|
19
24
|
alias_method :to_json, :raw
|
20
25
|
|
21
26
|
def error_message
|
22
|
-
|
27
|
+
parsed_message =
|
28
|
+
begin
|
29
|
+
raw.dig('message')
|
30
|
+
rescue JSON::ParserError
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
parsed_message || "#{code}: #{raw_response.body}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def skip
|
37
|
+
raw['skip']
|
38
|
+
end
|
39
|
+
|
40
|
+
def total
|
41
|
+
raw['total']
|
23
42
|
end
|
24
43
|
|
25
44
|
def next_page?
|
26
45
|
return unless raw.key? 'items'
|
27
46
|
|
28
|
-
|
47
|
+
page_items.length + skip < total
|
29
48
|
end
|
30
49
|
|
31
50
|
def next_page
|
32
51
|
return unless next_page?
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
52
|
+
return @next_page if @next_page
|
53
|
+
|
54
|
+
query = (@request[:query] || {}).merge({
|
55
|
+
skip: page_items.length + skip
|
56
|
+
})
|
57
|
+
np =
|
58
|
+
_instrument 'page', url: @request[:url], query: query do
|
59
|
+
@client.get(@request[:url], query)
|
60
|
+
end
|
61
|
+
@next_page = np.assert_ok!
|
41
62
|
end
|
42
63
|
|
43
64
|
def initialize(client, request, raw_response)
|
@@ -48,13 +69,13 @@ class WCC::Contentful::SimpleClient
|
|
48
69
|
end
|
49
70
|
|
50
71
|
def assert_ok!
|
51
|
-
return self if
|
72
|
+
return self if status >= 200 && status < 300
|
52
73
|
|
53
|
-
raise ApiError[
|
74
|
+
raise ApiError[status], self
|
54
75
|
end
|
55
76
|
|
56
77
|
def each_page(&block)
|
57
|
-
raise ArgumentError, 'Not a collection response' unless
|
78
|
+
raise ArgumentError, 'Not a collection response' unless page_items
|
58
79
|
|
59
80
|
ret =
|
60
81
|
Enumerator.new do |y|
|
@@ -75,19 +96,21 @@ class WCC::Contentful::SimpleClient
|
|
75
96
|
end
|
76
97
|
|
77
98
|
def items
|
78
|
-
each_page.flat_map
|
79
|
-
|
80
|
-
|
99
|
+
each_page.flat_map(&:page_items)
|
100
|
+
end
|
101
|
+
|
102
|
+
def page_items
|
103
|
+
raw['items']
|
81
104
|
end
|
82
105
|
|
83
106
|
def count
|
84
|
-
|
107
|
+
total
|
85
108
|
end
|
86
109
|
|
87
110
|
def first
|
88
|
-
raise ArgumentError, 'Not a collection response' unless
|
111
|
+
raise ArgumentError, 'Not a collection response' unless page_items
|
89
112
|
|
90
|
-
|
113
|
+
page_items.first
|
91
114
|
end
|
92
115
|
|
93
116
|
def includes
|
@@ -115,7 +138,13 @@ class WCC::Contentful::SimpleClient
|
|
115
138
|
def next_page
|
116
139
|
return unless next_page?
|
117
140
|
|
118
|
-
|
141
|
+
url = raw['nextPageUrl']
|
142
|
+
next_page =
|
143
|
+
_instrument 'page', url: url do
|
144
|
+
@client.get(url)
|
145
|
+
end
|
146
|
+
|
147
|
+
@next_page ||= SyncResponse.new(next_page)
|
119
148
|
@next_page.assert_ok!
|
120
149
|
end
|
121
150
|
|
@@ -129,7 +158,7 @@ class WCC::Contentful::SimpleClient
|
|
129
158
|
end
|
130
159
|
|
131
160
|
def each_page
|
132
|
-
raise ArgumentError, 'Not a collection response' unless
|
161
|
+
raise ArgumentError, 'Not a collection response' unless page_items
|
133
162
|
|
134
163
|
ret =
|
135
164
|
Enumerator.new do |y|
|
@@ -168,6 +197,10 @@ class WCC::Contentful::SimpleClient
|
|
168
197
|
case code
|
169
198
|
when 404
|
170
199
|
NotFoundError
|
200
|
+
when 401
|
201
|
+
UnauthorizedError
|
202
|
+
when 429
|
203
|
+
RateLimitError
|
171
204
|
else
|
172
205
|
ApiError
|
173
206
|
end
|
@@ -181,4 +214,10 @@ class WCC::Contentful::SimpleClient
|
|
181
214
|
|
182
215
|
class NotFoundError < ApiError
|
183
216
|
end
|
217
|
+
|
218
|
+
class UnauthorizedError < ApiError
|
219
|
+
end
|
220
|
+
|
221
|
+
class RateLimitError < ApiError
|
222
|
+
end
|
184
223
|
end
|