api_navigator 0.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 +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +26 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +3 -0
- data/CONTRIBUTING.md +4 -0
- data/Dangerfile +2 -0
- data/Gemfile +23 -0
- data/Guardfile +5 -0
- data/LICENSE +22 -0
- data/README.md +5 -0
- data/RELEASING.md +4 -0
- data/Rakefile +34 -0
- data/UPGRADING.md +4 -0
- data/api_navigator.gemspec +23 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/fixtures_2.rb +253 -0
- data/lib/api_navigator.rb +45 -0
- data/lib/api_navigator/attributes.rb +20 -0
- data/lib/api_navigator/collection_hash.rb +90 -0
- data/lib/api_navigator/curie.rb +47 -0
- data/lib/api_navigator/entry_point.rb +157 -0
- data/lib/api_navigator/link.rb +160 -0
- data/lib/api_navigator/link_collection.rb +63 -0
- data/lib/api_navigator/resource.rb +130 -0
- data/lib/api_navigator/resources/collection_resource.rb +41 -0
- data/lib/api_navigator/resources/member_resource.rb +63 -0
- data/lib/api_navigator/version.rb +3 -0
- data/lib/faraday/connection.rb +17 -0
- data/spec/fixtures/requests.rb +157 -0
- data/spec/fixtures/sample.json +108 -0
- data/spec/lib/api_navigator/attribute_spec.rb +36 -0
- data/spec/lib/api_navigator/collection_hash_spec.rb +71 -0
- data/spec/lib/api_navigator/entry_point_spec.rb +185 -0
- data/spec/lib/api_navigator/link_collection_spec.rb +77 -0
- data/spec/lib/api_navigator/link_spec.rb +343 -0
- data/spec/lib/api_navigator/resource_spec.rb +368 -0
- data/spec/spec_helper.rb +112 -0
- data/spec/support/book_resource.rb +10 -0
- data/spec/support/request_helper.rb +8 -0
- metadata +172 -0
@@ -0,0 +1,343 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ApiNavigator
|
4
|
+
describe Link do
|
5
|
+
let(:entry_point) do
|
6
|
+
EntryPoint.new('http://api.example.org/')
|
7
|
+
end
|
8
|
+
|
9
|
+
%w[type deprecation name profile title hreflang].each do |prop|
|
10
|
+
describe prop do
|
11
|
+
it 'returns the property value' do
|
12
|
+
link = Link.new('key', { prop => 'value' }, entry_point)
|
13
|
+
expect(link.send("_#{prop}")).to be == 'value'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns nil if the property is not present' do
|
17
|
+
link = Link.new('key', {}, entry_point)
|
18
|
+
expect(link.send("_#{prop}")).to be_nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '_templated?' do
|
24
|
+
it 'returns true if the link is templated' do
|
25
|
+
link = Link.new('key', { 'templated' => true }, entry_point)
|
26
|
+
|
27
|
+
expect(link._templated?).to be_truthy
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns false if the link is not templated' do
|
31
|
+
link = Link.new('key', {}, entry_point)
|
32
|
+
|
33
|
+
expect(link._templated?).to be_falsey
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '_variables' do
|
38
|
+
it 'returns a list of required variables' do
|
39
|
+
link = Link.new('key', { 'href' => '/orders{?id,owner}', 'templated' => true }, entry_point)
|
40
|
+
|
41
|
+
expect(link._variables).to match_array %w[id owner]
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns an empty array for untemplated links' do
|
45
|
+
link = Link.new('key', { 'href' => '/orders' }, entry_point)
|
46
|
+
|
47
|
+
expect(link._variables).to be_empty
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context '_expand templated links' do
|
52
|
+
describe 'required argument' do
|
53
|
+
it 'builds a Link with the templated URI representation' do
|
54
|
+
link = Link.new('key', { 'href' => '/orders/{id}', 'templated' => true }, entry_point)
|
55
|
+
expect(link._expand(id: '1')._url).to be == '/orders/1'
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'expands an uri template without variables' do
|
59
|
+
link = Link.new('key', { 'href' => '/orders/{id}', 'templated' => true }, entry_point)
|
60
|
+
expect(link._expand._url).to be == '/orders/'
|
61
|
+
expect(link._url).to be == '/orders/'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'query string argument' do
|
66
|
+
it 'builds a Link with the templated URI representation' do
|
67
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
68
|
+
expect(link._expand(id: '1')._url).to be == '/orders?id=1'
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'expands an uri template without variables' do
|
72
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
73
|
+
expect(link._expand._url).to be == '/orders'
|
74
|
+
expect(link._url).to be == '/orders'
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'does not expand unknown variables' do
|
78
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
79
|
+
expect(link._expand(unknown: '1')._url).to be == '/orders'
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'only expands known variables' do
|
83
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
84
|
+
expect(link._expand(unknown: '1', id: '2')._url).to be == '/orders?id=2'
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'only expands templated links' do
|
88
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => false }, entry_point)
|
89
|
+
expect(link._expand(id: '1')._url).to be == '/orders{?id}'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '_url' do
|
95
|
+
it 'expands an uri template without variables' do
|
96
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
97
|
+
|
98
|
+
expect(link._url).to be == '/orders'
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'expands an uri template with variables' do
|
102
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point, id: 1)
|
103
|
+
|
104
|
+
expect(link._url).to be == '/orders?id=1'
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'does not expand an uri template with unknown variables' do
|
108
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point, unknown: 1)
|
109
|
+
|
110
|
+
expect(link._url).to be == '/orders'
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'only expands known variables in a uri template' do
|
114
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point, unknown: 1, id: 2)
|
115
|
+
|
116
|
+
expect(link._url).to be == '/orders?id=2'
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'returns the link when no uri template' do
|
120
|
+
link = Link.new('key', { 'href' => '/orders' }, entry_point)
|
121
|
+
|
122
|
+
expect(link._url).to be == '/orders'
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'aliases to_s to _url' do
|
126
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point, id: 1)
|
127
|
+
|
128
|
+
expect(link.to_s).to be == '/orders?id=1'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '_resource' do
|
133
|
+
it 'builds a resource with the link href representation' do
|
134
|
+
expect(Resource).to receive(:new)
|
135
|
+
|
136
|
+
link = Link.new('key', { 'href' => '/' }, entry_point)
|
137
|
+
|
138
|
+
stub_request(entry_point.connection) do |stub|
|
139
|
+
stub.get('http://api.example.org/') { [200, {}, nil] }
|
140
|
+
end
|
141
|
+
|
142
|
+
link._resource
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe 'get' do
|
147
|
+
it 'sends a GET request with the link url' do
|
148
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
149
|
+
|
150
|
+
stub_request(entry_point.connection) do |stub|
|
151
|
+
stub.get('http://api.example.org/productions/1') { [200, {}, nil] }
|
152
|
+
end
|
153
|
+
|
154
|
+
expect(link._get).to be_kind_of Resource
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'raises exceptions by default' do
|
158
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
159
|
+
|
160
|
+
stub_request(entry_point.connection) do |stub|
|
161
|
+
stub.get('http://api.example.org/productions/1') { [400, {}, nil] }
|
162
|
+
end
|
163
|
+
|
164
|
+
expect { link._get }.to raise_error Faraday::ClientError
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '_options' do
|
169
|
+
it 'sends a OPTIONS request with the link url' do
|
170
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
171
|
+
|
172
|
+
stub_request(entry_point.connection) do |stub|
|
173
|
+
stub.options('http://api.example.org/productions/1') { [200, {}, nil] }
|
174
|
+
end
|
175
|
+
|
176
|
+
expect(link._options).to be_kind_of Resource
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe '_head' do
|
181
|
+
it 'sends a HEAD request with the link url' do
|
182
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
183
|
+
|
184
|
+
stub_request(entry_point.connection) do |stub|
|
185
|
+
stub.head('http://api.example.org/productions/1') { [200, {}, nil] }
|
186
|
+
end
|
187
|
+
|
188
|
+
expect(link._head).to be_kind_of Resource
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe '_delete' do
|
193
|
+
it 'sends a DELETE request with the link url' do
|
194
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
195
|
+
|
196
|
+
stub_request(entry_point.connection) do |stub|
|
197
|
+
stub.delete('http://api.example.org/productions/1') { [200, {}, nil] }
|
198
|
+
end
|
199
|
+
|
200
|
+
expect(link._delete).to be_kind_of Resource
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe '_post' do
|
205
|
+
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
206
|
+
|
207
|
+
it 'sends a POST request with the link url and params' do
|
208
|
+
stub_request(entry_point.connection) do |stub|
|
209
|
+
stub.post('http://api.example.org/productions/1') { [200, {}, nil] }
|
210
|
+
end
|
211
|
+
|
212
|
+
expect(link._post('foo' => 'bar')).to be_kind_of Resource
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'defaults params to an empty hash' do
|
216
|
+
stub_request(entry_point.connection) do |stub|
|
217
|
+
stub.post('http://api.example.org/productions/1') { [200, {}, nil] }
|
218
|
+
end
|
219
|
+
|
220
|
+
expect(link._post).to be_kind_of Resource
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe '_put' do
|
225
|
+
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
226
|
+
|
227
|
+
it 'sends a PUT request with the link url and params' do
|
228
|
+
stub_request(entry_point.connection) do |stub|
|
229
|
+
stub.put('http://api.example.org/productions/1', '{"foo":"bar"}') { [200, {}, nil] }
|
230
|
+
end
|
231
|
+
|
232
|
+
expect(link._put('foo' => 'bar')).to be_kind_of Resource
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'defaults params to an empty hash' do
|
236
|
+
stub_request(entry_point.connection) do |stub|
|
237
|
+
stub.put('http://api.example.org/productions/1') { [200, {}, nil] }
|
238
|
+
end
|
239
|
+
|
240
|
+
expect(link._put).to be_kind_of Resource
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe '_patch' do
|
245
|
+
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
246
|
+
|
247
|
+
it 'sends a PATCH request with the link url and params' do
|
248
|
+
stub_request(entry_point.connection) do |stub|
|
249
|
+
stub.patch('http://api.example.org/productions/1', '{"foo":"bar"}') { [200, {}, nil] }
|
250
|
+
end
|
251
|
+
|
252
|
+
expect(link._patch('foo' => 'bar')).to be_kind_of Resource
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'defaults params to an empty hash' do
|
256
|
+
stub_request(entry_point.connection) do |stub|
|
257
|
+
stub.patch('http://api.example.org/productions/1') { [200, {}, nil] }
|
258
|
+
end
|
259
|
+
|
260
|
+
expect(link._patch).to be_kind_of Resource
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe 'inspect' do
|
265
|
+
it 'outputs a custom-friendly output' do
|
266
|
+
link = Link.new('key', { 'href' => '/productions/1' }, 'foo')
|
267
|
+
|
268
|
+
expect(link.inspect).to include 'Link'
|
269
|
+
expect(link.inspect).to include '"href"=>"/productions/1"'
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
describe 'method_missing' do
|
275
|
+
describe 'delegation' do
|
276
|
+
it 'delegates when link key matches' do
|
277
|
+
resource = Resource.from_representation({ '_links' => { 'orders' => { 'href' => '/orders' } } }, entry_point)
|
278
|
+
|
279
|
+
stub_request(entry_point.connection) do |stub|
|
280
|
+
stub.get('http://api.example.org/orders') { [200, {}, { 'data' => [{'data' => {'id' => 1 }}] }] }
|
281
|
+
end
|
282
|
+
|
283
|
+
expect(resource.orders.first.id).to be == 1
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'can handle false values in the response' do
|
287
|
+
resource = Resource.from_representation({ '_links' => { 'orders' => { 'href' => '/orders' } } }, entry_point)
|
288
|
+
|
289
|
+
stub_request(entry_point.connection) do |stub|
|
290
|
+
stub.get('http://api.example.org/orders') { [200, {}, { 'data' => {'any' => false }}] }
|
291
|
+
end
|
292
|
+
|
293
|
+
expect(resource.orders.any).to be_falsey
|
294
|
+
end
|
295
|
+
|
296
|
+
it "doesn't delegate when link key doesn't match" do
|
297
|
+
resource = Resource.from_representation({ '_links' => { 'foos' => { 'href' => '/orders' } } }, entry_point)
|
298
|
+
|
299
|
+
stub_request(entry_point.connection) do |stub|
|
300
|
+
stub.get('http://api.example.org/orders') { [200, {}, { 'data' => [{ 'data' => { 'id' => 1 }}] }] }
|
301
|
+
end
|
302
|
+
|
303
|
+
expect(resource.foos.first.id).to be == 1
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
describe 'resource' do
|
308
|
+
before do
|
309
|
+
stub_request(entry_point.connection) do |stub|
|
310
|
+
stub.get('http://myapi.org/orders') { [200, {}, { 'data' => {'any' => false }}] }
|
311
|
+
end
|
312
|
+
|
313
|
+
Resource.stub(:new) { resource }
|
314
|
+
end
|
315
|
+
|
316
|
+
let(:resource) { double('Resource') }
|
317
|
+
let(:link) { Link.new('orders', { 'href' => 'http://myapi.org/orders' }, entry_point) }
|
318
|
+
|
319
|
+
it 'delegates unkown methods to the resource' do
|
320
|
+
expect(Resource).to receive(:new) {resource }.at_least(1)
|
321
|
+
expect(resource).to receive(:unknown_method)
|
322
|
+
|
323
|
+
link.unknown_method
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'raises an error when the method does not exist in the resource' do
|
327
|
+
expect { link.this_method_does_not_exist }.to raise_error NoMethodError
|
328
|
+
end
|
329
|
+
|
330
|
+
# it 'responds to missing methods' do
|
331
|
+
# expect(resource).to receive(:respond_to?).with('orders') { false }
|
332
|
+
|
333
|
+
# expect(link.respond_to?(:hui)).to be_falsey
|
334
|
+
# end
|
335
|
+
|
336
|
+
it 'does not delegate to_ary to resource' do
|
337
|
+
expect(resource).to receive(:to_ary).never
|
338
|
+
expect([[link, link]].flatten).to be == [link, link]
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
@@ -0,0 +1,368 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ApiNavigator
|
4
|
+
describe Resource do
|
5
|
+
let(:entry_point) do
|
6
|
+
EntryPoint.new('http://api.example.org/', 'sample_client')
|
7
|
+
end
|
8
|
+
|
9
|
+
%w[type deprecation name profile title hreflang].each do |prop|
|
10
|
+
describe prop do
|
11
|
+
it 'returns the property value' do
|
12
|
+
link = Link.new('key', { prop => 'value' }, entry_point)
|
13
|
+
expect(link.send("_#{prop}")).to be == 'value'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns nil if the property is not present' do
|
17
|
+
link = Link.new('key', {}, entry_point)
|
18
|
+
expect(link.send("_#{prop}")).to be_nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '_templated?' do
|
25
|
+
it 'returns true if the link is templated' do
|
26
|
+
link = Link.new('key', { 'templated' => true }, entry_point)
|
27
|
+
|
28
|
+
expect(link._templated?).to be_truthy
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns false if the link is not templated' do
|
32
|
+
link = Link.new('key', {}, entry_point)
|
33
|
+
|
34
|
+
expect(link._templated?).to be_falsey
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '_variables' do
|
39
|
+
it 'returns a list of required variables' do
|
40
|
+
link = Link.new('key', { 'href' => '/orders{?id,owner}', 'templated' => true }, entry_point)
|
41
|
+
|
42
|
+
expect(link._variables).to match_array %w[id owner]
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns an empty array for untemplated links' do
|
46
|
+
link = Link.new('key', { 'href' => '/orders' }, entry_point)
|
47
|
+
|
48
|
+
expect(link._variables).to be_empty
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context '_expand templated links' do
|
53
|
+
describe 'required argument' do
|
54
|
+
it 'builds a Link with the templated URI representation' do
|
55
|
+
link = Link.new('key', { 'href' => '/orders/{id}', 'templated' => true }, entry_point)
|
56
|
+
expect(link._expand(id: '1')._url).to be == '/orders/1'
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'expands an uri template without variables' do
|
60
|
+
link = Link.new('key', { 'href' => '/orders/{id}', 'templated' => true }, entry_point)
|
61
|
+
expect(link._expand._url).to be == '/orders/'
|
62
|
+
expect(link._url).to be == '/orders/'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'query string argument' do
|
67
|
+
it 'builds a Link with the templated URI representation' do
|
68
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
69
|
+
expect(link._expand(id: '1')._url).to be == '/orders?id=1'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'expands an uri template without variables' do
|
73
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
74
|
+
expect(link._expand._url).to be == '/orders'
|
75
|
+
expect(link._url).to be == '/orders'
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'does not expand unknown variables' do
|
79
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
80
|
+
expect(link._expand(unknown: '1')._url).to be == '/orders'
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'only expands known variables' do
|
84
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
85
|
+
expect(link._expand(unknown: '1', id: '2')._url).to be == '/orders?id=2'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'only expands templated links' do
|
89
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => false }, entry_point)
|
90
|
+
expect(link._expand(id: '1')._url).to be == '/orders{?id}'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '_url' do
|
96
|
+
it 'expands an uri template without variables' do
|
97
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point)
|
98
|
+
|
99
|
+
expect(link._url).to be == '/orders'
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'expands an uri template with variables' do
|
103
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point, id: 1)
|
104
|
+
|
105
|
+
expect(link._url).to be == '/orders?id=1'
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'does not expand an uri template with unknown variables' do
|
109
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point, unknown: 1)
|
110
|
+
|
111
|
+
expect(link._url).to be == '/orders'
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'only expands known variables in a uri template' do
|
115
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point, unknown: 1, id: 2)
|
116
|
+
|
117
|
+
expect(link._url).to be == '/orders?id=2'
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'returns the link when no uri template' do
|
121
|
+
link = Link.new('key', { 'href' => '/orders' }, entry_point)
|
122
|
+
|
123
|
+
expect(link._url).to be == '/orders'
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'aliases to_s to _url' do
|
127
|
+
link = Link.new('key', { 'href' => '/orders{?id}', 'templated' => true }, entry_point, id: 1)
|
128
|
+
|
129
|
+
expect(link.to_s).to be == '/orders?id=1'
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe '_resource' do
|
134
|
+
it 'builds a resource with the link href representation' do
|
135
|
+
expect(Resource).to receive(:new)
|
136
|
+
|
137
|
+
link = Link.new('key', { 'href' => '/' }, entry_point)
|
138
|
+
|
139
|
+
stub_request(entry_point.connection) do |stub|
|
140
|
+
stub.get('http://api.example.org/') { [200, {}, nil] }
|
141
|
+
end
|
142
|
+
|
143
|
+
link._resource
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'get' do
|
148
|
+
it 'sends a GET request with the link url' do
|
149
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
150
|
+
|
151
|
+
stub_request(entry_point.connection) do |stub|
|
152
|
+
stub.get('http://api.example.org/productions/1') { [200, {}, nil] }
|
153
|
+
end
|
154
|
+
|
155
|
+
expect(link._get).to be_kind_of Resource
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'raises exceptions by default' do
|
159
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
160
|
+
|
161
|
+
stub_request(entry_point.connection) do |stub|
|
162
|
+
stub.get('http://api.example.org/productions/1') { [400, {}, nil] }
|
163
|
+
end
|
164
|
+
|
165
|
+
expect { link._get }.to raise_error Faraday::ClientError
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe '_options' do
|
170
|
+
it 'sends a OPTIONS request with the link url' do
|
171
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
172
|
+
|
173
|
+
stub_request(entry_point.connection) do |stub|
|
174
|
+
stub.options('http://api.example.org/productions/1') { [200, {}, nil] }
|
175
|
+
end
|
176
|
+
|
177
|
+
expect(link._options).to be_kind_of Resource
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe '_head' do
|
182
|
+
it 'sends a HEAD request with the link url' do
|
183
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
184
|
+
|
185
|
+
stub_request(entry_point.connection) do |stub|
|
186
|
+
stub.head('http://api.example.org/productions/1') { [200, {}, nil] }
|
187
|
+
end
|
188
|
+
|
189
|
+
expect(link._head).to be_kind_of Resource
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '_delete' do
|
194
|
+
it 'sends a DELETE request with the link url' do
|
195
|
+
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
196
|
+
|
197
|
+
stub_request(entry_point.connection) do |stub|
|
198
|
+
stub.delete('http://api.example.org/productions/1') { [200, {}, nil] }
|
199
|
+
end
|
200
|
+
|
201
|
+
expect(link._delete).to be_kind_of Resource
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe '_post' do
|
206
|
+
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
207
|
+
|
208
|
+
it 'sends a POST request with the link url and params' do
|
209
|
+
stub_request(entry_point.connection) do |stub|
|
210
|
+
stub.post('http://api.example.org/productions/1') { [200, {}, nil] }
|
211
|
+
end
|
212
|
+
|
213
|
+
expect(link._post('foo' => 'bar')).to be_kind_of Resource
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'defaults params to an empty hash' do
|
217
|
+
stub_request(entry_point.connection) do |stub|
|
218
|
+
stub.post('http://api.example.org/productions/1') { [200, {}, nil] }
|
219
|
+
end
|
220
|
+
|
221
|
+
expect(link._post).to be_kind_of Resource
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe '_put' do
|
226
|
+
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
227
|
+
|
228
|
+
it 'sends a PUT request with the link url and params' do
|
229
|
+
stub_request(entry_point.connection) do |stub|
|
230
|
+
stub.put('http://api.example.org/productions/1', '{"foo":"bar"}') { [200, {}, nil] }
|
231
|
+
end
|
232
|
+
|
233
|
+
expect(link._put('foo' => 'bar')).to be_kind_of Resource
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'defaults params to an empty hash' do
|
237
|
+
stub_request(entry_point.connection) do |stub|
|
238
|
+
stub.put('http://api.example.org/productions/1') { [200, {}, nil] }
|
239
|
+
end
|
240
|
+
|
241
|
+
expect(link._put).to be_kind_of Resource
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe '_patch' do
|
246
|
+
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
247
|
+
|
248
|
+
it 'sends a PATCH request with the link url and params' do
|
249
|
+
stub_request(entry_point.connection) do |stub|
|
250
|
+
stub.patch('http://api.example.org/productions/1', '{"foo":"bar"}') { [200, {}, nil] }
|
251
|
+
end
|
252
|
+
|
253
|
+
expect(link._patch('foo' => 'bar')).to be_kind_of Resource
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'defaults params to an empty hash' do
|
257
|
+
stub_request(entry_point.connection) do |stub|
|
258
|
+
stub.patch('http://api.example.org/productions/1') { [200, {}, nil] }
|
259
|
+
end
|
260
|
+
|
261
|
+
expect(link._patch).to be_kind_of Resource
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
describe 'inspect' do
|
266
|
+
it 'outputs a custom-friendly output' do
|
267
|
+
link = Link.new('key', { 'href' => '/productions/1' }, 'foo')
|
268
|
+
|
269
|
+
expect(link.inspect).to include 'Link'
|
270
|
+
expect(link.inspect).to include '"href"=>"/productions/1"'
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
|
275
|
+
describe 'method_missing' do
|
276
|
+
describe 'delegation' do
|
277
|
+
it 'delegates when link key matches' do
|
278
|
+
resource = Resource.from_representation({ '_links' => { 'orders' => { 'href' => '/orders' } } }, entry_point)
|
279
|
+
|
280
|
+
stub_request(entry_point.connection) do |stub|
|
281
|
+
stub.get('http://api.example.org/orders') { [200, {}, { 'data' => [{'data' => {'id' => 1 }}] }] }
|
282
|
+
end
|
283
|
+
|
284
|
+
expect(resource.orders.first.id).to be == 1
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'delegates to data when data and link identifier is present' do
|
288
|
+
resource = Resource.from_representation({
|
289
|
+
'data' => { 'orders' => [ 'data' => { 'id' => 9 }] },
|
290
|
+
'_links' => { 'orders' => { 'href' => '/orders' } }
|
291
|
+
}, entry_point)
|
292
|
+
|
293
|
+
stub_request(entry_point.connection) do |stub|
|
294
|
+
stub.get('http://api.example.org/orders') { [200, {}, { 'data' => [{'data' => {'id' => 1 }}] }] }
|
295
|
+
end
|
296
|
+
|
297
|
+
expect(resource.orders.first.id).to be == 9
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'can handle false values in the response' do
|
301
|
+
resource = Resource.from_representation({ '_links' => { 'orders' => { 'href' => '/orders' } } }, entry_point)
|
302
|
+
|
303
|
+
stub_request(entry_point.connection) do |stub|
|
304
|
+
stub.get('http://api.example.org/orders') { [200, {}, { 'data' => {'any' => false }}] }
|
305
|
+
end
|
306
|
+
|
307
|
+
expect(resource.orders.any).to be_falsey
|
308
|
+
end
|
309
|
+
|
310
|
+
it "doesn't delegate when link key doesn't match" do
|
311
|
+
resource = Resource.from_representation({ '_links' => { 'foos' => { 'href' => '/orders' } } }, entry_point)
|
312
|
+
|
313
|
+
stub_request(entry_point.connection) do |stub|
|
314
|
+
stub.get('http://api.example.org/orders') { [200, {}, { 'data' => [{ 'data' => { 'id' => 1 }}] }] }
|
315
|
+
end
|
316
|
+
|
317
|
+
expect(resource.foos.first.id).to be == 1
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
describe "MemberResource instance creation" do
|
322
|
+
it "builds a resource of specific class if registered" do
|
323
|
+
ApiNavigator.register('sample_client')
|
324
|
+
ApiNavigator.register_resource('book', BookResource, client_identifier: 'sample_client')
|
325
|
+
|
326
|
+
resource = Resource.from_representation({
|
327
|
+
'data' => { 'id' => 1 },
|
328
|
+
'_meta' => { 'type' => 'book'} ,
|
329
|
+
}, entry_point)
|
330
|
+
|
331
|
+
expect(resource).to be_kind_of(BookResource)
|
332
|
+
expect(resource.foo).to be == 'bar'
|
333
|
+
expect(resource.id).to be == 1
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
describe 'resource' do
|
338
|
+
before do
|
339
|
+
stub_request(entry_point.connection) do |stub|
|
340
|
+
stub.get('http://myapi.org/orders') { [200, {}, { 'data' => {'any' => false }}] }
|
341
|
+
end
|
342
|
+
|
343
|
+
Resource.stub(:new) { resource }
|
344
|
+
end
|
345
|
+
|
346
|
+
|
347
|
+
let(:resource) { double('Resource') }
|
348
|
+
let(:link) { Link.new('orders', { 'href' => 'http://myapi.org/orders' }, entry_point) }
|
349
|
+
|
350
|
+
it 'delegates unkown methods to the resource' do
|
351
|
+
expect(Resource).to receive(:new) {resource }.at_least(1)
|
352
|
+
expect(resource).to receive(:unknown_method)
|
353
|
+
|
354
|
+
link.unknown_method
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'raises an error when the method does not exist in the resource' do
|
358
|
+
expect { link.this_method_does_not_exist }.to raise_error NoMethodError
|
359
|
+
end
|
360
|
+
|
361
|
+
it 'does not delegate to_ary to resource' do
|
362
|
+
expect(resource).to receive(:to_ary).never
|
363
|
+
expect([[link, link]].flatten).to be == [link, link]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|