flexirest 1.3.35 → 1.4.0

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.
@@ -0,0 +1,392 @@
1
+ require 'spec_helper'
2
+
3
+ class JsonAPIAssociationExampleAuthor < Flexirest::Base; end
4
+
5
+ class JsonAPIAssociationExampleTag < Flexirest::Base
6
+ proxy :json_api
7
+ has_many :authors, JsonAPIAssociationExampleAuthor
8
+ end
9
+
10
+ class JsonAPIAssociationExampleAuthor < Flexirest::Base
11
+ proxy :json_api
12
+ has_one :tag, JsonAPIAssociationExampleTag
13
+ end
14
+
15
+ class JsonAPIExampleArticle < Flexirest::Base
16
+ proxy :json_api
17
+ has_many :tags, JsonAPIAssociationExampleTag
18
+ has_one :author, JsonAPIAssociationExampleAuthor
19
+
20
+ faker1 = {
21
+ data: {
22
+ id: 1, type: 'articles', attributes: { item: 'item one' },
23
+ relationships: {
24
+ 'tags' => { data: [{ id: 1, type: 'tags' }, { id: 2, type: 'tags' }] }
25
+ }
26
+ },
27
+ included: [
28
+ { id: 1, type: 'tags', attributes: { item: 'item two' } },
29
+ { id: 2, type: 'tags', attributes: { item: 'item three' } }
30
+ ]
31
+ }
32
+ faker2 = {
33
+ data: [
34
+ {
35
+ id: 1, type: 'articles', attributes: { item: 'item one' },
36
+ relationships: {
37
+ 'tags' => { data: [{ id: 1, type: 'tags' }, { id: 2, type: 'tags' }] }
38
+ }
39
+ },
40
+ {
41
+ id: 2, type: 'articles', attributes: { item: 'item four' },
42
+ relationships: {
43
+ 'tags' => { data: [{ id: 2, type: 'tags' }] }
44
+ }
45
+ }
46
+ ],
47
+ included: [
48
+ { id: 1, type: 'tags', attributes: { item: 'item two' } },
49
+ { id: 2, type: 'tags', attributes: { item: 'item three' } }
50
+ ]
51
+ }
52
+ faker3 = {
53
+ data: {
54
+ id: 1, type: 'articles', attributes: { item: 'item one' },
55
+ relationships: { 'author' => { data: { id: 1, type: 'authors' } } }
56
+ },
57
+ included: [{ id: 1, type: 'authors', attributes: { item: 'item two' } }]
58
+ }
59
+ faker4 = {
60
+ data: {
61
+ id: 1, type: 'articles', attributes: { item: 'item one' },
62
+ relationships: { 'author' => { data: { id: 1, type: 'authors' } } }
63
+ },
64
+ included: [
65
+ { id: 1, type: 'authors', attributes: { item: 'item two' },
66
+ relationships: { 'tag' => { data: { id: 1, type: 'tags' } } } },
67
+ { id: 1, type: 'tags', attributes: { item: 'item three' } }
68
+ ]
69
+ }
70
+ faker5 = {
71
+ data: {
72
+ id: 1, type: 'articles', attributes: { item: 'item one' },
73
+ relationships: { 'tags' => { data: [{ id: 1, type: 'tags' }] } }
74
+ },
75
+ included: [
76
+ { id: 1, type: 'tags', attributes: { item: 'item three' },
77
+ relationships: { 'authors' => { data: [{ id: 1, type: 'tags' }] } } },
78
+ { id: 1, type: 'authors', attributes: { item: 'item two' } }
79
+ ]
80
+ }
81
+ faker6 = {
82
+ data: {
83
+ id: 1, type: 'articles', attributes: { item: 'item one' },
84
+ relationships: { 'tags' => { data: [] }, 'author' => { data: nil } }
85
+ }
86
+ }
87
+
88
+ get(
89
+ :find,
90
+ '/articles/:id',
91
+ fake: faker1.to_json,
92
+ fake_content_type: 'application/vnd.api+json'
93
+ )
94
+
95
+ get(
96
+ :find_all,
97
+ '/articles',
98
+ fake: faker2.to_json,
99
+ fake_content_type: 'application/vnd.api+json'
100
+ )
101
+
102
+ get(
103
+ :find_single_author,
104
+ '/articles/:id',
105
+ fake: faker3.to_json,
106
+ fake_content_type: 'application/vnd.api+json'
107
+ )
108
+
109
+ get(
110
+ :find_single_nested,
111
+ '/articles/:id',
112
+ fake: faker4.to_json,
113
+ fake_content_type: 'application/vnd.api+json'
114
+ )
115
+
116
+ get(
117
+ :find_multi_nested,
118
+ '/articles/:id',
119
+ fake: faker5.to_json,
120
+ fake_content_type: 'application/vnd.api+json'
121
+ )
122
+
123
+ get(
124
+ :no_assocs,
125
+ '/articles/:id',
126
+ fake: faker6.to_json,
127
+ fake_content_type: 'application/vnd.api+json'
128
+ )
129
+ end
130
+
131
+ module JsonAPIExample
132
+ class Author < Flexirest::Base
133
+ proxy :json_api
134
+ base_url 'http://www.example.com'
135
+
136
+ author_faker = {
137
+ data: { id: 1, type: 'authors', attributes: { item: 'item three' } }
138
+ }
139
+
140
+ get(
141
+ :find_author,
142
+ '/articles/:article_id/author',
143
+ fake: author_faker.to_json,
144
+ fake_content_type: 'application/vnd.api+json'
145
+ )
146
+ end
147
+
148
+ class Tag < Flexirest::Base
149
+ proxy :json_api
150
+ base_url 'http://www.example.com'
151
+
152
+ tags_faker = {
153
+ data: [{ id: 1, type: 'tags', attributes: { item: 'item two' } }]
154
+ }
155
+
156
+ get(
157
+ :find_tags,
158
+ '/articles/:article_id/tags',
159
+ fake: tags_faker.to_json,
160
+ fake_content_type: 'application/vnd.api+json'
161
+ )
162
+ end
163
+
164
+ class Article < Flexirest::Base
165
+ base_url 'http://www.example.com'
166
+ proxy :json_api
167
+ has_one :author, Author
168
+ has_many :tags, Tag
169
+
170
+ faker = {
171
+ data: { id: 1, type: 'articles', attributes: { item: 'item one' } }
172
+ }
173
+
174
+ faker_lazy = {
175
+ data: {
176
+ id: 1, type: 'articles', attributes: { item: 'item one' },
177
+ relationships: {
178
+ 'tags' => {
179
+ links: {
180
+ self: 'http://www.example.com/articles/1/relationships/tags',
181
+ related: 'http://www.example.com/articles/1/tags'
182
+ }
183
+ },
184
+ 'author' => {
185
+ links: {
186
+ self: 'http://www.example.com/articles/1/relationships/author',
187
+ related: 'http://www.example.com/articles/1/author'
188
+ }
189
+ }
190
+ }
191
+ }
192
+ }
193
+
194
+ get(
195
+ :find_lazy,
196
+ '/articles/:id',
197
+ fake: faker_lazy.to_json,
198
+ fake_content_type: 'application/vnd.api+json'
199
+ )
200
+
201
+ get(
202
+ :find,
203
+ '/articles/:id',
204
+ fake: faker.to_json,
205
+ fake_content_type: 'application/vnd.api+json'
206
+ )
207
+
208
+ post :create, '/articles', fake_content_type: 'application/vnd.api+json'
209
+
210
+ patch(
211
+ :update,
212
+ '/articles/:id',
213
+ fake_content_type: 'application/vnd.api+json'
214
+ )
215
+
216
+ delete(
217
+ :delete,
218
+ '/articles/:id',
219
+ fake_content_type: 'application/vnd.api+json'
220
+ )
221
+ end
222
+
223
+ class AuthorAlias < Flexirest::Base
224
+ alias_type :authors
225
+ proxy :json_api
226
+ end
227
+
228
+ class ArticleAlias < Flexirest::Base
229
+ alias_type :articles
230
+ base_url 'http://www.example.com'
231
+ proxy :json_api
232
+ has_one :author, AuthorAlias
233
+
234
+ faker = {
235
+ data: { id: 1, type: 'articles', attributes: { item: 'item one' } }
236
+ }
237
+
238
+ get(
239
+ :find,
240
+ '/articles/:id',
241
+ fake: faker.to_json,
242
+ fake_content_type: 'application/vnd.api+json'
243
+ )
244
+
245
+ patch :update, '/articles/:id'
246
+ end
247
+ end
248
+
249
+ describe 'JSON API' do
250
+ let(:subject) { JsonAPIExampleArticle }
251
+ let(:article) { JsonAPIExample::Article }
252
+ let(:tags) { JsonAPIExample::Tag }
253
+ let(:author) { JsonAPIExample::Author }
254
+
255
+ context 'responses' do
256
+ it 'should return the data object if the response contains only one data instance' do
257
+ expect(subject.find(1)).to be_an_instance_of(JsonAPIExampleArticle)
258
+ end
259
+
260
+ it 'should return a Flexirest::ResultIterator if the response contains more than one data instance' do
261
+ expect(subject.find_all).to be_an_instance_of(Flexirest::ResultIterator)
262
+ end
263
+ end
264
+
265
+ context 'attributes' do
266
+ it 'should return the attributes as part of the data instance' do
267
+ expect(subject.find(1).item).to_not be_nil
268
+ end
269
+
270
+ it 'should return the association\'s attributes as part of the association instance' do
271
+ expect(subject.includes(:author).find_single_author(1).author.item).to_not be_nil
272
+ end
273
+ end
274
+
275
+ context 'associations' do
276
+ it 'should retrieve the resource\'s associations via its relationships object' do
277
+ expect(subject.includes(:tags).find(1).tags.size).to eq(2)
278
+ end
279
+
280
+ it 'should retrieve the response object if the relationship type is singular' do
281
+ expect(subject.includes(:author).find_single_author(1).author).to be_an_instance_of(JsonAPIAssociationExampleAuthor)
282
+ end
283
+
284
+ it 'should retrieve a Flexirest::ResultIterator if the relationship type is plural' do
285
+ expect(subject.includes(:tags).find(1).tags).to be_an_instance_of(Flexirest::ResultIterator)
286
+ end
287
+
288
+ it 'should retrieve nested linked resources' do
289
+ expect(subject.includes(author: [:tag]).find_single_nested(1).author.tag).to be_an_instance_of(JsonAPIAssociationExampleTag)
290
+ expect(subject.includes(author: [:tag]).find_single_nested(1).author.tag.id).to_not be_nil
291
+ expect(subject.includes(tags: [:authors]).find_multi_nested(1).tags.first.authors.first).to be_an_instance_of(JsonAPIAssociationExampleAuthor)
292
+ expect(subject.includes(tags: [:authors]).find_multi_nested(1).tags.first.authors.first.id).to_not be_nil
293
+ end
294
+
295
+ it 'should retrieve a nil if the singular relationship type is empty' do
296
+ expect(subject.includes(:author).no_assocs(1).author).to be_nil
297
+ end
298
+
299
+ it 'should retrieve empty array if the plural relationship type is empty' do
300
+ expect(subject.includes(:tags).no_assocs(1).tags).to be_empty
301
+ end
302
+ end
303
+
304
+ context 'lazy loading' do
305
+ it 'should fetch association lazily' do
306
+ stub_request(:get, /www.example.com\/articles\/1\/tags/)
307
+ .to_return(body: tags.find_tags(article_id: 1).to_json)
308
+ stub_request(:get, /www.example.com\/articles\/1\/author/)
309
+ .to_return(body: author.find_author(article_id: 1).to_json)
310
+
311
+ expect(article.find_lazy(1).tags).to be_an_instance_of(Flexirest::LazyAssociationLoader)
312
+ expect(article.find_lazy(1).tags.count).to be_an(Integer)
313
+ expect(article.find_lazy(1).tags.first.id).to_not be_nil
314
+ expect(article.find_lazy(1).author).to be_an_instance_of(JsonAPIExample::Author)
315
+ expect(article.find_lazy(1).author.id).to_not be_nil
316
+ end
317
+ end
318
+
319
+ context 'client' do
320
+ it 'should request with json api format, and expect a json api response' do
321
+ expect_any_instance_of(Flexirest::Connection).to receive(:post) { |_, _, _, options|
322
+ expect(options[:headers]).to include('Content-Type' => 'application/vnd.api+json')
323
+ expect(options[:headers]).to include('Accept' => 'application/vnd.api+json')
324
+ }.and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{}', response_headers:{})))
325
+ JsonAPIExample::Article.new.create
326
+ end
327
+
328
+ it 'should perform a post request in proper json api format' do
329
+ expect_any_instance_of(Flexirest::Connection).to receive(:post) { |_, path, data|
330
+ hash = MultiJson.load(data)
331
+ expect(path).to eq('/articles')
332
+ expect(hash['data']).to_not be_nil
333
+ expect(hash['data']['id']).to be_nil
334
+ expect(hash['data']['type']).to eq('articles')
335
+ expect(hash['data']['relationships']['author']['data']['type']).to eq('authors')
336
+ expect(hash['data']['relationships']['tags']['data'].first['type']).to eq('tags')
337
+ }.and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{}', response_headers:{})))
338
+ author = JsonAPIExample::Author.new
339
+ tag = JsonAPIExample::Tag.new
340
+ article = JsonAPIExample::Article.new
341
+ article.item = 'item one'
342
+ article.author = author
343
+ article.tags = [tag]
344
+ article.create
345
+ end
346
+
347
+ it 'should raise a Flexirest error when two different classes are in one relationship' do
348
+ author = JsonAPIExample::Author.new
349
+ tag = JsonAPIExample::Tag.new
350
+ article = JsonAPIExample::Article.new
351
+ article.item = 'item one'
352
+ article.tags = [tag, author]
353
+ expect(lambda { article.create }).to raise_error(Exception)
354
+ end
355
+
356
+ it 'should perform a patch request in proper json api format' do
357
+ expect_any_instance_of(Flexirest::Connection).to receive(:patch) { |_, path, data|
358
+ hash = MultiJson.load(data)
359
+ expect(path).to eq('/articles/1')
360
+ expect(hash['data']).to_not be_nil
361
+ expect(hash['data']['id']).to_not be_nil
362
+ expect(hash['data']['type']).to_not be_nil
363
+ }.and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{}', response_headers:{})))
364
+ article = JsonAPIExample::Article.find(1)
365
+ article.item = 'item one'
366
+ article.update
367
+ end
368
+
369
+ it 'should perform a delete request in proper json api format' do
370
+ expect_any_instance_of(Flexirest::Connection).to receive(:delete) { |_, path, data|
371
+ expect(path).to eq('/articles/1')
372
+ expect(data).to eq('')
373
+ }.and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{}', response_headers:{})))
374
+ JsonAPIExample::Article.find(1).delete
375
+ end
376
+
377
+ it 'should have placed the right type value in the request' do
378
+ expect_any_instance_of(Flexirest::Connection).to receive(:patch) { |_, _, data|
379
+ hash = MultiJson.load(data)
380
+ expect(hash['data']['type']).to eq(JsonAPIExample::ArticleAlias.alias_type.to_s)
381
+ expect(hash['data']['relationships']['author']['data']['type']).to eq(JsonAPIExample::AuthorAlias.alias_type.to_s)
382
+ }.and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{}', response_headers:{})))
383
+ author = JsonAPIExample::AuthorAlias.new
384
+ author.id = 1
385
+ article = JsonAPIExample::ArticleAlias.find(1)
386
+ article.item = 'item one'
387
+ article.author = author
388
+ article.update
389
+ end
390
+
391
+ end
392
+ end
@@ -501,6 +501,7 @@ describe Flexirest::Request do
501
501
  with("/create", "first_name=John&should_disappear=true", an_instance_of(Hash)).
502
502
  and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"first_name\":\"John\", \"id\":1234}", response_headers:{}, status:200)))
503
503
  expect(Flexirest::Logger).to receive(:info).with(%r'Requesting http://www.example.com/create')
504
+ allow(Flexirest::Logger).to receive(:debug)
504
505
  expect(Flexirest::Logger).to receive(:debug).at_least(1).times.with(%r'(Response received \d+ bytes|Trying to read from cache)')
505
506
 
506
507
  object = ExampleClient.new(first_name:"John", should_disappear:true)
@@ -514,6 +515,7 @@ describe Flexirest::Request do
514
515
  with("/create", "first_name=John&should_disappear=true", an_instance_of(Hash)).
515
516
  and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"first_name\":\"John\", \"id\":1234}", response_headers:{}, status:200)))
516
517
  expect(Flexirest::Logger).to receive(:info).with(%r'Requesting http://www.example.com/create')
518
+ allow(Flexirest::Logger).to receive(:debug)
517
519
  expect(Flexirest::Logger).to receive(:debug).at_least(1).times.with(%r'(Response received \d+ bytes|Trying to read from cache)')
518
520
 
519
521
  object = ExampleClient.new(first_name:"John", should_disappear:true)
@@ -526,7 +528,7 @@ describe Flexirest::Request do
526
528
  with("/create", "first_name=John&should_disappear=true", an_instance_of(Hash)).
527
529
  and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"first_name\":\"John\", \"id\":1234}", response_headers:{}, status:200)))
528
530
  expect(Flexirest::Logger).to receive(:debug).with(/ POST /)
529
- allow(Flexirest::Logger).to receive(:debug).with(any_args)
531
+ allow(Flexirest::Logger).to receive(:debug)
530
532
 
531
533
  object = VerboseExampleClient.new(first_name:"John", should_disappear:true)
532
534
  object.create
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flexirest
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.35
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Jeffries
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-13 00:00:00.000000000 Z
11
+ date: 2017-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -242,6 +242,7 @@ files:
242
242
  - lib/flexirest/connection_manager.rb
243
243
  - lib/flexirest/headers_list.rb
244
244
  - lib/flexirest/instrumentation.rb
245
+ - lib/flexirest/json_api_proxy.rb
245
246
  - lib/flexirest/lazy_association_loader.rb
246
247
  - lib/flexirest/lazy_loader.rb
247
248
  - lib/flexirest/logger.rb
@@ -266,6 +267,7 @@ files:
266
267
  - spec/lib/flexirest_spec.rb
267
268
  - spec/lib/headers_list_spec.rb
268
269
  - spec/lib/instrumentation_spec.rb
270
+ - spec/lib/json_api_spec.rb
269
271
  - spec/lib/lazy_association_loader_spec.rb
270
272
  - spec/lib/lazy_loader_spec.rb
271
273
  - spec/lib/logger_spec.rb
@@ -317,6 +319,7 @@ test_files:
317
319
  - spec/lib/flexirest_spec.rb
318
320
  - spec/lib/headers_list_spec.rb
319
321
  - spec/lib/instrumentation_spec.rb
322
+ - spec/lib/json_api_spec.rb
320
323
  - spec/lib/lazy_association_loader_spec.rb
321
324
  - spec/lib/lazy_loader_spec.rb
322
325
  - spec/lib/logger_spec.rb