grape 1.3.1 → 1.5.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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -1
  3. data/LICENSE +1 -1
  4. data/README.md +104 -21
  5. data/UPGRADING.md +265 -39
  6. data/lib/grape.rb +2 -2
  7. data/lib/grape/api.rb +2 -2
  8. data/lib/grape/api/instance.rb +29 -28
  9. data/lib/grape/dsl/helpers.rb +1 -0
  10. data/lib/grape/dsl/inside_route.rb +69 -36
  11. data/lib/grape/dsl/parameters.rb +7 -3
  12. data/lib/grape/dsl/routing.rb +2 -4
  13. data/lib/grape/dsl/validations.rb +18 -1
  14. data/lib/grape/eager_load.rb +1 -1
  15. data/lib/grape/endpoint.rb +8 -6
  16. data/lib/grape/http/headers.rb +1 -0
  17. data/lib/grape/middleware/base.rb +2 -1
  18. data/lib/grape/middleware/error.rb +10 -12
  19. data/lib/grape/middleware/formatter.rb +3 -3
  20. data/lib/grape/middleware/stack.rb +21 -8
  21. data/lib/grape/middleware/versioner/header.rb +1 -1
  22. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  23. data/lib/grape/path.rb +2 -2
  24. data/lib/grape/request.rb +1 -1
  25. data/lib/grape/router.rb +30 -43
  26. data/lib/grape/router/attribute_translator.rb +26 -5
  27. data/lib/grape/router/route.rb +3 -22
  28. data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
  29. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
  30. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
  31. data/lib/grape/util/base_inheritable.rb +11 -8
  32. data/lib/grape/util/lazy_value.rb +1 -0
  33. data/lib/grape/util/reverse_stackable_values.rb +3 -1
  34. data/lib/grape/util/stackable_values.rb +3 -1
  35. data/lib/grape/validations/attributes_iterator.rb +8 -0
  36. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  37. data/lib/grape/validations/params_scope.rb +8 -6
  38. data/lib/grape/validations/single_attribute_iterator.rb +1 -1
  39. data/lib/grape/validations/types.rb +6 -5
  40. data/lib/grape/validations/types/array_coercer.rb +14 -5
  41. data/lib/grape/validations/types/build_coercer.rb +5 -8
  42. data/lib/grape/validations/types/custom_type_coercer.rb +14 -2
  43. data/lib/grape/validations/types/dry_type_coercer.rb +36 -1
  44. data/lib/grape/validations/types/file.rb +15 -13
  45. data/lib/grape/validations/types/json.rb +40 -36
  46. data/lib/grape/validations/types/primitive_coercer.rb +11 -5
  47. data/lib/grape/validations/types/set_coercer.rb +6 -4
  48. data/lib/grape/validations/types/variant_collection_coercer.rb +1 -1
  49. data/lib/grape/validations/validator_factory.rb +1 -1
  50. data/lib/grape/validations/validators/as.rb +1 -1
  51. data/lib/grape/validations/validators/base.rb +4 -5
  52. data/lib/grape/validations/validators/coerce.rb +3 -10
  53. data/lib/grape/validations/validators/default.rb +3 -5
  54. data/lib/grape/validations/validators/except_values.rb +1 -1
  55. data/lib/grape/validations/validators/multiple_params_base.rb +2 -1
  56. data/lib/grape/validations/validators/regexp.rb +1 -1
  57. data/lib/grape/validations/validators/values.rb +1 -1
  58. data/lib/grape/version.rb +1 -1
  59. data/spec/grape/api/instance_spec.rb +50 -0
  60. data/spec/grape/api_spec.rb +75 -0
  61. data/spec/grape/dsl/inside_route_spec.rb +182 -33
  62. data/spec/grape/endpoint/declared_spec.rb +601 -0
  63. data/spec/grape/endpoint_spec.rb +0 -521
  64. data/spec/grape/entity_spec.rb +6 -0
  65. data/spec/grape/integration/rack_sendfile_spec.rb +12 -8
  66. data/spec/grape/middleware/auth/strategies_spec.rb +1 -1
  67. data/spec/grape/middleware/error_spec.rb +1 -1
  68. data/spec/grape/middleware/formatter_spec.rb +1 -1
  69. data/spec/grape/middleware/stack_spec.rb +3 -1
  70. data/spec/grape/path_spec.rb +4 -4
  71. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +13 -3
  72. data/spec/grape/validations/params_scope_spec.rb +26 -0
  73. data/spec/grape/validations/single_attribute_iterator_spec.rb +17 -6
  74. data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
  75. data/spec/grape/validations/types/primitive_coercer_spec.rb +65 -5
  76. data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
  77. data/spec/grape/validations/types_spec.rb +1 -1
  78. data/spec/grape/validations/validators/coerce_spec.rb +317 -29
  79. data/spec/grape/validations/validators/default_spec.rb +170 -0
  80. data/spec/grape/validations/validators/except_values_spec.rb +1 -0
  81. data/spec/grape/validations/validators/values_spec.rb +1 -1
  82. data/spec/grape/validations_spec.rb +290 -18
  83. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  84. data/spec/spec_helper.rb +0 -10
  85. data/spec/support/chunks.rb +14 -0
  86. data/spec/support/versioned_helpers.rb +3 -5
  87. metadata +18 -8
@@ -0,0 +1,601 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Grape::Endpoint do
6
+ subject { Class.new(Grape::API) }
7
+
8
+ def app
9
+ subject
10
+ end
11
+
12
+ describe '#declared' do
13
+ before do
14
+ subject.format :json
15
+ subject.params do
16
+ requires :first
17
+ optional :second
18
+ optional :third, default: 'third-default'
19
+ optional :multiple_types, types: [Integer, String]
20
+ optional :nested, type: Hash do
21
+ optional :fourth
22
+ optional :fifth
23
+ optional :nested_two, type: Hash do
24
+ optional :sixth
25
+ optional :nested_three, type: Hash do
26
+ optional :seventh
27
+ end
28
+ end
29
+ optional :nested_arr, type: Array do
30
+ optional :eighth
31
+ end
32
+ optional :empty_arr, type: Array
33
+ optional :empty_typed_arr, type: Array[String]
34
+ optional :empty_hash, type: Hash
35
+ optional :empty_set, type: Set
36
+ optional :empty_typed_set, type: Set[String]
37
+ end
38
+ optional :arr, type: Array do
39
+ optional :nineth
40
+ end
41
+ optional :empty_arr, type: Array
42
+ optional :empty_typed_arr, type: Array[String]
43
+ optional :empty_hash, type: Hash
44
+ optional :empty_set, type: Set
45
+ optional :empty_typed_set, type: Set[String]
46
+ end
47
+ end
48
+
49
+ context 'when params are not built with default class' do
50
+ it 'returns an object that corresponds with the params class - hash with indifferent access' do
51
+ subject.params do
52
+ build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
53
+ end
54
+ subject.get '/declared' do
55
+ d = declared(params, include_missing: true)
56
+ { declared_class: d.class.to_s }
57
+ end
58
+
59
+ get '/declared?first=present'
60
+ expect(JSON.parse(last_response.body)['declared_class']).to eq('ActiveSupport::HashWithIndifferentAccess')
61
+ end
62
+
63
+ it 'returns an object that corresponds with the params class - hashie mash' do
64
+ subject.params do
65
+ build_with Grape::Extensions::Hashie::Mash::ParamBuilder
66
+ end
67
+ subject.get '/declared' do
68
+ d = declared(params, include_missing: true)
69
+ { declared_class: d.class.to_s }
70
+ end
71
+
72
+ get '/declared?first=present'
73
+ expect(JSON.parse(last_response.body)['declared_class']).to eq('Hashie::Mash')
74
+ end
75
+
76
+ it 'returns an object that corresponds with the params class - hash' do
77
+ subject.params do
78
+ build_with Grape::Extensions::Hash::ParamBuilder
79
+ end
80
+ subject.get '/declared' do
81
+ d = declared(params, include_missing: true)
82
+ { declared_class: d.class.to_s }
83
+ end
84
+
85
+ get '/declared?first=present'
86
+ expect(JSON.parse(last_response.body)['declared_class']).to eq('Hash')
87
+ end
88
+ end
89
+
90
+ it 'should show nil for nested params if include_missing is true' do
91
+ subject.get '/declared' do
92
+ declared(params, include_missing: true)
93
+ end
94
+
95
+ get '/declared?first=present'
96
+ expect(last_response.status).to eq(200)
97
+ expect(JSON.parse(last_response.body)['nested']['fourth']).to be_nil
98
+ end
99
+
100
+ it 'should show nil for multiple allowed types if include_missing is true' do
101
+ subject.get '/declared' do
102
+ declared(params, include_missing: true)
103
+ end
104
+
105
+ get '/declared?first=present'
106
+ expect(last_response.status).to eq(200)
107
+ expect(JSON.parse(last_response.body)['multiple_types']).to be_nil
108
+ end
109
+
110
+ it 'does not work in a before filter' do
111
+ subject.before do
112
+ declared(params)
113
+ end
114
+ subject.get('/declared') { declared(params) }
115
+
116
+ expect { get('/declared') }.to raise_error(
117
+ Grape::DSL::InsideRoute::MethodNotYetAvailable
118
+ )
119
+ end
120
+
121
+ it 'has as many keys as there are declared params' do
122
+ subject.get '/declared' do
123
+ declared(params)
124
+ end
125
+ get '/declared?first=present'
126
+ expect(last_response.status).to eq(200)
127
+ expect(JSON.parse(last_response.body).keys.size).to eq(11)
128
+ end
129
+
130
+ it 'has a optional param with default value all the time' do
131
+ subject.get '/declared' do
132
+ declared(params)
133
+ end
134
+ get '/declared?first=one'
135
+ expect(last_response.status).to eq(200)
136
+ expect(JSON.parse(last_response.body)['third']).to eql('third-default')
137
+ end
138
+
139
+ it 'builds nested params' do
140
+ subject.get '/declared' do
141
+ declared(params)
142
+ end
143
+
144
+ get '/declared?first=present&nested[fourth]=1'
145
+ expect(last_response.status).to eq(200)
146
+ expect(JSON.parse(last_response.body)['nested'].keys.size).to eq 9
147
+ end
148
+
149
+ it 'builds arrays correctly' do
150
+ subject.params do
151
+ requires :first
152
+ optional :second, type: Array
153
+ end
154
+ subject.post('/declared') { declared(params) }
155
+
156
+ post '/declared', first: 'present', second: ['present']
157
+ expect(last_response.status).to eq(201)
158
+
159
+ body = JSON.parse(last_response.body)
160
+ expect(body['second']).to eq(['present'])
161
+ end
162
+
163
+ it 'builds nested params when given array' do
164
+ subject.get '/dummy' do
165
+ end
166
+ subject.params do
167
+ requires :first
168
+ optional :second
169
+ optional :third, default: 'third-default'
170
+ optional :nested, type: Array do
171
+ optional :fourth
172
+ end
173
+ end
174
+ subject.get '/declared' do
175
+ declared(params)
176
+ end
177
+
178
+ get '/declared?first=present&nested[][fourth]=1&nested[][fourth]=2'
179
+ expect(last_response.status).to eq(200)
180
+ expect(JSON.parse(last_response.body)['nested'].size).to eq 2
181
+ end
182
+
183
+ context 'when the param is missing and include_missing=false' do
184
+ before do
185
+ subject.get('/declared') { declared(params, include_missing: false) }
186
+ end
187
+
188
+ it 'sets nested objects to be nil' do
189
+ get '/declared?first=present'
190
+ expect(last_response.status).to eq(200)
191
+ expect(JSON.parse(last_response.body)['nested']).to be_nil
192
+ end
193
+ end
194
+
195
+ context 'when the param is missing and include_missing=true' do
196
+ before do
197
+ subject.get('/declared') { declared(params, include_missing: true) }
198
+ end
199
+
200
+ it 'sets objects with type=Hash to be a hash' do
201
+ get '/declared?first=present'
202
+ expect(last_response.status).to eq(200)
203
+
204
+ body = JSON.parse(last_response.body)
205
+ expect(body['empty_hash']).to eq({})
206
+ expect(body['nested']).to be_a(Hash)
207
+ expect(body['nested']['empty_hash']).to eq({})
208
+ expect(body['nested']['nested_two']).to be_a(Hash)
209
+ end
210
+
211
+ it 'sets objects with type=Set to be a set' do
212
+ get '/declared?first=present'
213
+ expect(last_response.status).to eq(200)
214
+
215
+ body = JSON.parse(last_response.body)
216
+ expect(['#<Set: {}>', []]).to include(body['empty_set'])
217
+ expect(['#<Set: {}>', []]).to include(body['empty_typed_set'])
218
+ expect(['#<Set: {}>', []]).to include(body['nested']['empty_set'])
219
+ expect(['#<Set: {}>', []]).to include(body['nested']['empty_typed_set'])
220
+ end
221
+
222
+ it 'sets objects with type=Array to be an array' do
223
+ get '/declared?first=present'
224
+ expect(last_response.status).to eq(200)
225
+
226
+ body = JSON.parse(last_response.body)
227
+ expect(body['empty_arr']).to eq([])
228
+ expect(body['empty_typed_arr']).to eq([])
229
+ expect(body['arr']).to eq([])
230
+ expect(body['nested']['empty_arr']).to eq([])
231
+ expect(body['nested']['empty_typed_arr']).to eq([])
232
+ expect(body['nested']['nested_arr']).to eq([])
233
+ end
234
+
235
+ it 'includes all declared children when type=Hash' do
236
+ get '/declared?first=present'
237
+ expect(last_response.status).to eq(200)
238
+
239
+ body = JSON.parse(last_response.body)
240
+ expect(body['nested'].keys).to eq(%w[fourth fifth nested_two nested_arr empty_arr empty_typed_arr empty_hash empty_set empty_typed_set])
241
+ expect(body['nested']['nested_two'].keys).to eq(%w[sixth nested_three])
242
+ expect(body['nested']['nested_two']['nested_three'].keys).to eq(%w[seventh])
243
+ end
244
+ end
245
+
246
+ it 'filters out any additional params that are given' do
247
+ subject.get '/declared' do
248
+ declared(params)
249
+ end
250
+ get '/declared?first=one&other=two'
251
+ expect(last_response.status).to eq(200)
252
+ expect(JSON.parse(last_response.body).key?(:other)).to eq false
253
+ end
254
+
255
+ it 'stringifies if that option is passed' do
256
+ subject.get '/declared' do
257
+ declared(params, stringify: true)
258
+ end
259
+
260
+ get '/declared?first=one&other=two'
261
+ expect(last_response.status).to eq(200)
262
+ expect(JSON.parse(last_response.body)['first']).to eq 'one'
263
+ end
264
+
265
+ it 'does not include missing attributes if that option is passed' do
266
+ subject.get '/declared' do
267
+ error! 'expected nil', 400 if declared(params, include_missing: false).key?(:second)
268
+ ''
269
+ end
270
+
271
+ get '/declared?first=one&other=two'
272
+ expect(last_response.status).to eq(200)
273
+ end
274
+
275
+ it 'does not include renamed missing attributes if that option is passed' do
276
+ subject.params do
277
+ optional :renamed_original, as: :renamed
278
+ end
279
+ subject.get '/declared' do
280
+ error! 'expected nil', 400 if declared(params, include_missing: false).key?(:renamed)
281
+ ''
282
+ end
283
+
284
+ get '/declared?first=one&other=two'
285
+ expect(last_response.status).to eq(200)
286
+ end
287
+
288
+ it 'includes attributes with value that evaluates to false' do
289
+ subject.params do
290
+ requires :first
291
+ optional :boolean
292
+ end
293
+
294
+ subject.post '/declared' do
295
+ error!('expected false', 400) if declared(params, include_missing: false)[:boolean] != false
296
+ ''
297
+ end
298
+
299
+ post '/declared', ::Grape::Json.dump(first: 'one', boolean: false), 'CONTENT_TYPE' => 'application/json'
300
+ expect(last_response.status).to eq(201)
301
+ end
302
+
303
+ it 'includes attributes with value that evaluates to nil' do
304
+ subject.params do
305
+ requires :first
306
+ optional :second
307
+ end
308
+
309
+ subject.post '/declared' do
310
+ error!('expected nil', 400) unless declared(params, include_missing: false)[:second].nil?
311
+ ''
312
+ end
313
+
314
+ post '/declared', ::Grape::Json.dump(first: 'one', second: nil), 'CONTENT_TYPE' => 'application/json'
315
+ expect(last_response.status).to eq(201)
316
+ end
317
+
318
+ it 'includes missing attributes with defaults when there are nested hashes' do
319
+ subject.get '/dummy' do
320
+ end
321
+
322
+ subject.params do
323
+ requires :first
324
+ optional :second
325
+ optional :third, default: nil
326
+ optional :nested, type: Hash do
327
+ optional :fourth, default: nil
328
+ optional :fifth, default: nil
329
+ requires :nested_nested, type: Hash do
330
+ optional :sixth, default: 'sixth-default'
331
+ optional :seven, default: nil
332
+ end
333
+ end
334
+ end
335
+
336
+ subject.get '/declared' do
337
+ declared(params, include_missing: false)
338
+ end
339
+
340
+ get '/declared?first=present&nested[fourth]=&nested[nested_nested][sixth]=sixth'
341
+ json = JSON.parse(last_response.body)
342
+ expect(last_response.status).to eq(200)
343
+ expect(json['first']).to eq 'present'
344
+ expect(json['nested'].keys).to eq %w[fourth fifth nested_nested]
345
+ expect(json['nested']['fourth']).to eq ''
346
+ expect(json['nested']['nested_nested'].keys).to eq %w[sixth seven]
347
+ expect(json['nested']['nested_nested']['sixth']).to eq 'sixth'
348
+ end
349
+
350
+ it 'does not include missing attributes when there are nested hashes' do
351
+ subject.get '/dummy' do
352
+ end
353
+
354
+ subject.params do
355
+ requires :first
356
+ optional :second
357
+ optional :third
358
+ optional :nested, type: Hash do
359
+ optional :fourth
360
+ optional :fifth
361
+ end
362
+ end
363
+
364
+ subject.get '/declared' do
365
+ declared(params, include_missing: false)
366
+ end
367
+
368
+ get '/declared?first=present&nested[fourth]=4'
369
+ json = JSON.parse(last_response.body)
370
+ expect(last_response.status).to eq(200)
371
+ expect(json['first']).to eq 'present'
372
+ expect(json['nested'].keys).to eq %w[fourth]
373
+ expect(json['nested']['fourth']).to eq '4'
374
+ end
375
+ end
376
+
377
+ describe '#declared; call from child namespace' do
378
+ before do
379
+ subject.format :json
380
+ subject.namespace :parent do
381
+ params do
382
+ requires :parent_name, type: String
383
+ end
384
+
385
+ namespace ':parent_name' do
386
+ params do
387
+ requires :child_name, type: String
388
+ requires :child_age, type: Integer
389
+ end
390
+
391
+ namespace ':child_name' do
392
+ params do
393
+ requires :grandchild_name, type: String
394
+ end
395
+
396
+ get ':grandchild_name' do
397
+ {
398
+ 'params' => params,
399
+ 'without_parent_namespaces' => declared(params, include_parent_namespaces: false),
400
+ 'with_parent_namespaces' => declared(params, include_parent_namespaces: true)
401
+ }
402
+ end
403
+ end
404
+ end
405
+ end
406
+
407
+ get '/parent/foo/bar/baz', child_age: 5, extra: 'hello'
408
+ end
409
+
410
+ let(:parsed_response) { JSON.parse(last_response.body, symbolize_names: true) }
411
+
412
+ it { expect(last_response.status).to eq 200 }
413
+
414
+ context 'with include_parent_namespaces: false' do
415
+ it 'returns declared parameters only from current namespace' do
416
+ expect(parsed_response[:without_parent_namespaces]).to eq(
417
+ grandchild_name: 'baz'
418
+ )
419
+ end
420
+ end
421
+
422
+ context 'with include_parent_namespaces: true' do
423
+ it 'returns declared parameters from every parent namespace' do
424
+ expect(parsed_response[:with_parent_namespaces]).to eq(
425
+ parent_name: 'foo',
426
+ child_name: 'bar',
427
+ grandchild_name: 'baz',
428
+ child_age: 5
429
+ )
430
+ end
431
+ end
432
+
433
+ context 'without declaration' do
434
+ it 'returns all requested parameters' do
435
+ expect(parsed_response[:params]).to eq(
436
+ parent_name: 'foo',
437
+ child_name: 'bar',
438
+ grandchild_name: 'baz',
439
+ child_age: 5,
440
+ extra: 'hello'
441
+ )
442
+ end
443
+ end
444
+ end
445
+
446
+ describe '#declared; from a nested mounted endpoint' do
447
+ before do
448
+ doubly_mounted = Class.new(Grape::API)
449
+ doubly_mounted.namespace :more do
450
+ params do
451
+ requires :y, type: Integer
452
+ end
453
+ route_param :y do
454
+ get do
455
+ {
456
+ params: params,
457
+ declared_params: declared(params)
458
+ }
459
+ end
460
+ end
461
+ end
462
+
463
+ mounted = Class.new(Grape::API)
464
+ mounted.namespace :another do
465
+ params do
466
+ requires :mount_space, type: Integer
467
+ end
468
+ route_param :mount_space do
469
+ mount doubly_mounted
470
+ end
471
+ end
472
+
473
+ subject.format :json
474
+ subject.namespace :something do
475
+ params do
476
+ requires :id, type: Integer
477
+ end
478
+ resource ':id' do
479
+ mount mounted
480
+ end
481
+ end
482
+ end
483
+
484
+ it 'can access parent attributes' do
485
+ get '/something/123/another/456/more/789'
486
+ expect(last_response.status).to eq 200
487
+ json = JSON.parse(last_response.body, symbolize_names: true)
488
+
489
+ # test all three levels of params
490
+ expect(json[:declared_params][:y]).to eq 789
491
+ expect(json[:declared_params][:mount_space]).to eq 456
492
+ expect(json[:declared_params][:id]).to eq 123
493
+ end
494
+ end
495
+
496
+ describe '#declared; mixed nesting' do
497
+ before do
498
+ subject.format :json
499
+ subject.resource :users do
500
+ route_param :id, type: Integer, desc: 'ID desc' do
501
+ # Adding this causes route_setting(:declared_params) to be nil for the
502
+ # get block in namespace 'foo' below
503
+ get do
504
+ end
505
+
506
+ namespace 'foo' do
507
+ get do
508
+ {
509
+ params: params,
510
+ declared_params: declared(params),
511
+ declared_params_no_parent: declared(params, include_parent_namespaces: false)
512
+ }
513
+ end
514
+ end
515
+ end
516
+ end
517
+ end
518
+
519
+ it 'can access parent route_param' do
520
+ get '/users/123/foo', bar: 'bar'
521
+ expect(last_response.status).to eq 200
522
+ json = JSON.parse(last_response.body, symbolize_names: true)
523
+
524
+ expect(json[:declared_params][:id]).to eq 123
525
+ expect(json[:declared_params_no_parent][:id]).to eq nil
526
+ end
527
+ end
528
+
529
+ describe '#declared; with multiple route_param' do
530
+ before do
531
+ mounted = Class.new(Grape::API)
532
+ mounted.namespace :albums do
533
+ get do
534
+ declared(params)
535
+ end
536
+ end
537
+
538
+ subject.format :json
539
+ subject.namespace :artists do
540
+ route_param :id, type: Integer do
541
+ get do
542
+ declared(params)
543
+ end
544
+
545
+ params do
546
+ requires :filter, type: String
547
+ end
548
+ get :some_route do
549
+ declared(params)
550
+ end
551
+ end
552
+
553
+ route_param :artist_id, type: Integer do
554
+ namespace :compositions do
555
+ get do
556
+ declared(params)
557
+ end
558
+ end
559
+ end
560
+
561
+ route_param :compositor_id, type: Integer do
562
+ mount mounted
563
+ end
564
+ end
565
+ end
566
+
567
+ it 'return only :id without :artist_id' do
568
+ get '/artists/1'
569
+ json = JSON.parse(last_response.body, symbolize_names: true)
570
+
571
+ expect(json.key?(:id)).to be_truthy
572
+ expect(json.key?(:artist_id)).not_to be_truthy
573
+ end
574
+
575
+ it 'return only :artist_id without :id' do
576
+ get '/artists/1/compositions'
577
+ json = JSON.parse(last_response.body, symbolize_names: true)
578
+
579
+ expect(json.key?(:artist_id)).to be_truthy
580
+ expect(json.key?(:id)).not_to be_truthy
581
+ end
582
+
583
+ it 'return :filter and :id parameters in declared for second enpoint inside route_param' do
584
+ get '/artists/1/some_route', filter: 'some_filter'
585
+ json = JSON.parse(last_response.body, symbolize_names: true)
586
+
587
+ expect(json.key?(:filter)).to be_truthy
588
+ expect(json.key?(:id)).to be_truthy
589
+ expect(json.key?(:artist_id)).not_to be_truthy
590
+ end
591
+
592
+ it 'return :compositor_id for mounter in route_param' do
593
+ get '/artists/1/albums'
594
+ json = JSON.parse(last_response.body, symbolize_names: true)
595
+
596
+ expect(json.key?(:compositor_id)).to be_truthy
597
+ expect(json.key?(:id)).not_to be_truthy
598
+ expect(json.key?(:artist_id)).not_to be_truthy
599
+ end
600
+ end
601
+ end