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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +82 -1
- data/LICENSE +1 -1
- data/README.md +104 -21
- data/UPGRADING.md +265 -39
- data/lib/grape.rb +2 -2
- data/lib/grape/api.rb +2 -2
- data/lib/grape/api/instance.rb +29 -28
- data/lib/grape/dsl/helpers.rb +1 -0
- data/lib/grape/dsl/inside_route.rb +69 -36
- data/lib/grape/dsl/parameters.rb +7 -3
- data/lib/grape/dsl/routing.rb +2 -4
- data/lib/grape/dsl/validations.rb +18 -1
- data/lib/grape/eager_load.rb +1 -1
- data/lib/grape/endpoint.rb +8 -6
- data/lib/grape/http/headers.rb +1 -0
- data/lib/grape/middleware/base.rb +2 -1
- data/lib/grape/middleware/error.rb +10 -12
- data/lib/grape/middleware/formatter.rb +3 -3
- data/lib/grape/middleware/stack.rb +21 -8
- data/lib/grape/middleware/versioner/header.rb +1 -1
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
- data/lib/grape/path.rb +2 -2
- data/lib/grape/request.rb +1 -1
- data/lib/grape/router.rb +30 -43
- data/lib/grape/router/attribute_translator.rb +26 -5
- data/lib/grape/router/route.rb +3 -22
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
- data/lib/grape/util/base_inheritable.rb +11 -8
- data/lib/grape/util/lazy_value.rb +1 -0
- data/lib/grape/util/reverse_stackable_values.rb +3 -1
- data/lib/grape/util/stackable_values.rb +3 -1
- data/lib/grape/validations/attributes_iterator.rb +8 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/params_scope.rb +8 -6
- data/lib/grape/validations/single_attribute_iterator.rb +1 -1
- data/lib/grape/validations/types.rb +6 -5
- data/lib/grape/validations/types/array_coercer.rb +14 -5
- data/lib/grape/validations/types/build_coercer.rb +5 -8
- data/lib/grape/validations/types/custom_type_coercer.rb +14 -2
- data/lib/grape/validations/types/dry_type_coercer.rb +36 -1
- data/lib/grape/validations/types/file.rb +15 -13
- data/lib/grape/validations/types/json.rb +40 -36
- data/lib/grape/validations/types/primitive_coercer.rb +11 -5
- data/lib/grape/validations/types/set_coercer.rb +6 -4
- data/lib/grape/validations/types/variant_collection_coercer.rb +1 -1
- data/lib/grape/validations/validator_factory.rb +1 -1
- data/lib/grape/validations/validators/as.rb +1 -1
- data/lib/grape/validations/validators/base.rb +4 -5
- data/lib/grape/validations/validators/coerce.rb +3 -10
- data/lib/grape/validations/validators/default.rb +3 -5
- data/lib/grape/validations/validators/except_values.rb +1 -1
- data/lib/grape/validations/validators/multiple_params_base.rb +2 -1
- data/lib/grape/validations/validators/regexp.rb +1 -1
- data/lib/grape/validations/validators/values.rb +1 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/instance_spec.rb +50 -0
- data/spec/grape/api_spec.rb +75 -0
- data/spec/grape/dsl/inside_route_spec.rb +182 -33
- data/spec/grape/endpoint/declared_spec.rb +601 -0
- data/spec/grape/endpoint_spec.rb +0 -521
- data/spec/grape/entity_spec.rb +6 -0
- data/spec/grape/integration/rack_sendfile_spec.rb +12 -8
- data/spec/grape/middleware/auth/strategies_spec.rb +1 -1
- data/spec/grape/middleware/error_spec.rb +1 -1
- data/spec/grape/middleware/formatter_spec.rb +1 -1
- data/spec/grape/middleware/stack_spec.rb +3 -1
- data/spec/grape/path_spec.rb +4 -4
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +13 -3
- data/spec/grape/validations/params_scope_spec.rb +26 -0
- data/spec/grape/validations/single_attribute_iterator_spec.rb +17 -6
- data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +65 -5
- data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
- data/spec/grape/validations/types_spec.rb +1 -1
- data/spec/grape/validations/validators/coerce_spec.rb +317 -29
- data/spec/grape/validations/validators/default_spec.rb +170 -0
- data/spec/grape/validations/validators/except_values_spec.rb +1 -0
- data/spec/grape/validations/validators/values_spec.rb +1 -1
- data/spec/grape/validations_spec.rb +290 -18
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/spec_helper.rb +0 -10
- data/spec/support/chunks.rb +14 -0
- data/spec/support/versioned_helpers.rb +3 -5
- metadata +18 -8
@@ -154,6 +154,36 @@ describe Grape::Validations::CoerceValidator do
|
|
154
154
|
end
|
155
155
|
|
156
156
|
context 'coerces' do
|
157
|
+
context 'json' do
|
158
|
+
let(:headers) { { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' } }
|
159
|
+
|
160
|
+
it 'BigDecimal' do
|
161
|
+
subject.params do
|
162
|
+
requires :bigdecimal, type: BigDecimal
|
163
|
+
end
|
164
|
+
subject.post '/bigdecimal' do
|
165
|
+
"#{params[:bigdecimal].class} #{params[:bigdecimal].to_f}"
|
166
|
+
end
|
167
|
+
|
168
|
+
post '/bigdecimal', { bigdecimal: 45.1 }.to_json, headers
|
169
|
+
expect(last_response.status).to eq(201)
|
170
|
+
expect(last_response.body).to eq('BigDecimal 45.1')
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'Boolean' do
|
174
|
+
subject.params do
|
175
|
+
requires :boolean, type: Boolean
|
176
|
+
end
|
177
|
+
subject.post '/boolean' do
|
178
|
+
params[:boolean]
|
179
|
+
end
|
180
|
+
|
181
|
+
post '/boolean', { boolean: 'true' }.to_json, headers
|
182
|
+
expect(last_response.status).to eq(201)
|
183
|
+
expect(last_response.body).to eq('true')
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
157
187
|
it 'BigDecimal' do
|
158
188
|
subject.params do
|
159
189
|
requires :bigdecimal, coerce: BigDecimal
|
@@ -180,6 +210,23 @@ describe Grape::Validations::CoerceValidator do
|
|
180
210
|
expect(last_response.body).to eq(integer_class_name)
|
181
211
|
end
|
182
212
|
|
213
|
+
it 'String' do
|
214
|
+
subject.params do
|
215
|
+
requires :string, coerce: String
|
216
|
+
end
|
217
|
+
subject.get '/string' do
|
218
|
+
params[:string].class
|
219
|
+
end
|
220
|
+
|
221
|
+
get '/string', string: 45
|
222
|
+
expect(last_response.status).to eq(200)
|
223
|
+
expect(last_response.body).to eq('String')
|
224
|
+
|
225
|
+
get '/string', string: nil
|
226
|
+
expect(last_response.status).to eq(200)
|
227
|
+
expect(last_response.body).to eq('NilClass')
|
228
|
+
end
|
229
|
+
|
183
230
|
it 'is a custom type' do
|
184
231
|
subject.params do
|
185
232
|
requires :uri, coerce: SecureURIOnly
|
@@ -307,42 +354,60 @@ describe Grape::Validations::CoerceValidator do
|
|
307
354
|
expect(last_response.body).to eq('TrueClass')
|
308
355
|
end
|
309
356
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
end
|
314
|
-
subject.post '/upload' do
|
315
|
-
params[:file][:filename]
|
316
|
-
end
|
357
|
+
context 'File' do
|
358
|
+
let(:file) { Rack::Test::UploadedFile.new(__FILE__) }
|
359
|
+
let(:filename) { File.basename(__FILE__).to_s }
|
317
360
|
|
318
|
-
|
319
|
-
|
320
|
-
|
361
|
+
it 'Rack::Multipart::UploadedFile' do
|
362
|
+
subject.params do
|
363
|
+
requires :file, type: Rack::Multipart::UploadedFile
|
364
|
+
end
|
365
|
+
subject.post '/upload' do
|
366
|
+
params[:file][:filename]
|
367
|
+
end
|
321
368
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
end
|
369
|
+
post '/upload', file: file
|
370
|
+
expect(last_response.status).to eq(201)
|
371
|
+
expect(last_response.body).to eq(filename)
|
326
372
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
end
|
331
|
-
subject.post '/upload' do
|
332
|
-
params[:file][:filename]
|
373
|
+
post '/upload', file: 'not a file'
|
374
|
+
expect(last_response.status).to eq(400)
|
375
|
+
expect(last_response.body).to eq('file is invalid')
|
333
376
|
end
|
334
377
|
|
335
|
-
|
336
|
-
|
337
|
-
|
378
|
+
it 'File' do
|
379
|
+
subject.params do
|
380
|
+
requires :file, coerce: File
|
381
|
+
end
|
382
|
+
subject.post '/upload' do
|
383
|
+
params[:file][:filename]
|
384
|
+
end
|
338
385
|
|
339
|
-
|
340
|
-
|
341
|
-
|
386
|
+
post '/upload', file: file
|
387
|
+
expect(last_response.status).to eq(201)
|
388
|
+
expect(last_response.body).to eq(filename)
|
342
389
|
|
343
|
-
|
344
|
-
|
345
|
-
|
390
|
+
post '/upload', file: 'not a file'
|
391
|
+
expect(last_response.status).to eq(400)
|
392
|
+
expect(last_response.body).to eq('file is invalid')
|
393
|
+
|
394
|
+
post '/upload', file: { filename: 'fake file', tempfile: '/etc/passwd' }
|
395
|
+
expect(last_response.status).to eq(400)
|
396
|
+
expect(last_response.body).to eq('file is invalid')
|
397
|
+
end
|
398
|
+
|
399
|
+
it 'collection' do
|
400
|
+
subject.params do
|
401
|
+
requires :files, type: Array[File]
|
402
|
+
end
|
403
|
+
subject.post '/upload' do
|
404
|
+
params[:files].first[:filename]
|
405
|
+
end
|
406
|
+
|
407
|
+
post '/upload', files: [file]
|
408
|
+
expect(last_response.status).to eq(201)
|
409
|
+
expect(last_response.body).to eq(filename)
|
410
|
+
end
|
346
411
|
end
|
347
412
|
|
348
413
|
it 'Nests integers' do
|
@@ -359,6 +424,165 @@ describe Grape::Validations::CoerceValidator do
|
|
359
424
|
expect(last_response.status).to eq(200)
|
360
425
|
expect(last_response.body).to eq(integer_class_name)
|
361
426
|
end
|
427
|
+
|
428
|
+
context 'nil values' do
|
429
|
+
context 'primitive types' do
|
430
|
+
Grape::Validations::Types::PRIMITIVES.each do |type|
|
431
|
+
it 'respects the nil value' do
|
432
|
+
subject.params do
|
433
|
+
requires :param, type: type
|
434
|
+
end
|
435
|
+
subject.get '/nil_value' do
|
436
|
+
params[:param].class
|
437
|
+
end
|
438
|
+
|
439
|
+
get '/nil_value', param: nil
|
440
|
+
expect(last_response.status).to eq(200)
|
441
|
+
expect(last_response.body).to eq('NilClass')
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
context 'structures types' do
|
447
|
+
Grape::Validations::Types::STRUCTURES.each do |type|
|
448
|
+
it 'respects the nil value' do
|
449
|
+
subject.params do
|
450
|
+
requires :param, type: type
|
451
|
+
end
|
452
|
+
subject.get '/nil_value' do
|
453
|
+
params[:param].class
|
454
|
+
end
|
455
|
+
|
456
|
+
get '/nil_value', param: nil
|
457
|
+
expect(last_response.status).to eq(200)
|
458
|
+
expect(last_response.body).to eq('NilClass')
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
context 'special types' do
|
464
|
+
Grape::Validations::Types::SPECIAL.each_key do |type|
|
465
|
+
it 'respects the nil value' do
|
466
|
+
subject.params do
|
467
|
+
requires :param, type: type
|
468
|
+
end
|
469
|
+
subject.get '/nil_value' do
|
470
|
+
params[:param].class
|
471
|
+
end
|
472
|
+
|
473
|
+
get '/nil_value', param: nil
|
474
|
+
expect(last_response.status).to eq(200)
|
475
|
+
expect(last_response.body).to eq('NilClass')
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
context 'variant-member-type collections' do
|
480
|
+
[
|
481
|
+
Array[Integer, String],
|
482
|
+
[Integer, String, Array[Integer, String]]
|
483
|
+
].each do |type|
|
484
|
+
it 'respects the nil value' do
|
485
|
+
subject.params do
|
486
|
+
requires :param, type: type
|
487
|
+
end
|
488
|
+
subject.get '/nil_value' do
|
489
|
+
params[:param].class
|
490
|
+
end
|
491
|
+
|
492
|
+
get '/nil_value', param: nil
|
493
|
+
expect(last_response.status).to eq(200)
|
494
|
+
expect(last_response.body).to eq('NilClass')
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
context 'empty string' do
|
502
|
+
context 'primitive types' do
|
503
|
+
(Grape::Validations::Types::PRIMITIVES - [String]).each do |type|
|
504
|
+
it "is coerced to nil for type #{type}" do
|
505
|
+
subject.params do
|
506
|
+
requires :param, type: type
|
507
|
+
end
|
508
|
+
subject.get '/empty_string' do
|
509
|
+
params[:param].class
|
510
|
+
end
|
511
|
+
|
512
|
+
get '/empty_string', param: ''
|
513
|
+
expect(last_response.status).to eq(200)
|
514
|
+
expect(last_response.body).to eq('NilClass')
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
it 'is not coerced to nil for type String' do
|
519
|
+
subject.params do
|
520
|
+
requires :param, type: String
|
521
|
+
end
|
522
|
+
subject.get '/empty_string' do
|
523
|
+
params[:param].class
|
524
|
+
end
|
525
|
+
|
526
|
+
get '/empty_string', param: ''
|
527
|
+
expect(last_response.status).to eq(200)
|
528
|
+
expect(last_response.body).to eq('String')
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
context 'structures types' do
|
533
|
+
(Grape::Validations::Types::STRUCTURES - [Hash]).each do |type|
|
534
|
+
it "is coerced to nil for type #{type}" do
|
535
|
+
subject.params do
|
536
|
+
requires :param, type: type
|
537
|
+
end
|
538
|
+
subject.get '/empty_string' do
|
539
|
+
params[:param].class
|
540
|
+
end
|
541
|
+
|
542
|
+
get '/empty_string', param: ''
|
543
|
+
expect(last_response.status).to eq(200)
|
544
|
+
expect(last_response.body).to eq('NilClass')
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
context 'special types' do
|
550
|
+
(Grape::Validations::Types::SPECIAL.keys - [File, Rack::Multipart::UploadedFile]).each do |type|
|
551
|
+
it "is coerced to nil for type #{type}" do
|
552
|
+
subject.params do
|
553
|
+
requires :param, type: type
|
554
|
+
end
|
555
|
+
subject.get '/empty_string' do
|
556
|
+
params[:param].class
|
557
|
+
end
|
558
|
+
|
559
|
+
get '/empty_string', param: ''
|
560
|
+
expect(last_response.status).to eq(200)
|
561
|
+
expect(last_response.body).to eq('NilClass')
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
context 'variant-member-type collections' do
|
566
|
+
[
|
567
|
+
Array[Integer, String],
|
568
|
+
[Integer, String, Array[Integer, String]]
|
569
|
+
].each do |type|
|
570
|
+
it "is coerced to nil for type #{type}" do
|
571
|
+
subject.params do
|
572
|
+
requires :param, type: type
|
573
|
+
end
|
574
|
+
subject.get '/empty_string' do
|
575
|
+
params[:param].class
|
576
|
+
end
|
577
|
+
|
578
|
+
get '/empty_string', param: ''
|
579
|
+
expect(last_response.status).to eq(200)
|
580
|
+
expect(last_response.body).to eq('NilClass')
|
581
|
+
end
|
582
|
+
end
|
583
|
+
end
|
584
|
+
end
|
585
|
+
end
|
362
586
|
end
|
363
587
|
|
364
588
|
context 'using coerce_with' do
|
@@ -396,6 +620,30 @@ describe Grape::Validations::CoerceValidator do
|
|
396
620
|
expect(JSON.parse(last_response.body)).to eq(%w[a b c d])
|
397
621
|
end
|
398
622
|
|
623
|
+
it 'parses parameters with Array[Array[String]] type and coerce_with' do
|
624
|
+
subject.params do
|
625
|
+
requires :values, type: Array[Array[String]], coerce_with: ->(val) { val.is_a?(String) ? [val.split(/,/).map(&:strip)] : val }
|
626
|
+
end
|
627
|
+
subject.post '/coerce_nested_strings' do
|
628
|
+
params[:values]
|
629
|
+
end
|
630
|
+
|
631
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: 'a,b,c,d'), 'CONTENT_TYPE' => 'application/json'
|
632
|
+
expect(last_response.status).to eq(201)
|
633
|
+
expect(JSON.parse(last_response.body)).to eq([%w[a b c d]])
|
634
|
+
|
635
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: [%w[a c], %w[b]]), 'CONTENT_TYPE' => 'application/json'
|
636
|
+
expect(last_response.status).to eq(201)
|
637
|
+
expect(JSON.parse(last_response.body)).to eq([%w[a c], %w[b]])
|
638
|
+
|
639
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: [[]]), 'CONTENT_TYPE' => 'application/json'
|
640
|
+
expect(last_response.status).to eq(201)
|
641
|
+
expect(JSON.parse(last_response.body)).to eq([[]])
|
642
|
+
|
643
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: [['a', { bar: 0 }], ['b']]), 'CONTENT_TYPE' => 'application/json'
|
644
|
+
expect(last_response.status).to eq(400)
|
645
|
+
end
|
646
|
+
|
399
647
|
it 'parses parameters with Array[Integer] type' do
|
400
648
|
subject.params do
|
401
649
|
requires :values, type: Array[Integer], coerce_with: ->(val) { val.split(/\s+/).map(&:to_i) }
|
@@ -478,6 +726,46 @@ describe Grape::Validations::CoerceValidator do
|
|
478
726
|
expect(last_response.body).to eq('3')
|
479
727
|
end
|
480
728
|
|
729
|
+
context 'Integer type and coerce_with potentially returning nil' do
|
730
|
+
before do
|
731
|
+
subject.params do
|
732
|
+
requires :int, type: Integer, coerce_with: (lambda do |val|
|
733
|
+
if val == '0'
|
734
|
+
nil
|
735
|
+
elsif val.match?(/^-?\d+$/)
|
736
|
+
val.to_i
|
737
|
+
else
|
738
|
+
val
|
739
|
+
end
|
740
|
+
end)
|
741
|
+
end
|
742
|
+
subject.get '/' do
|
743
|
+
params[:int].class.to_s
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
747
|
+
it 'accepts value that coerces to nil' do
|
748
|
+
get '/', int: '0'
|
749
|
+
|
750
|
+
expect(last_response.status).to eq(200)
|
751
|
+
expect(last_response.body).to eq('NilClass')
|
752
|
+
end
|
753
|
+
|
754
|
+
it 'coerces to Integer' do
|
755
|
+
get '/', int: '1'
|
756
|
+
|
757
|
+
expect(last_response.status).to eq(200)
|
758
|
+
expect(last_response.body).to eq('Integer')
|
759
|
+
end
|
760
|
+
|
761
|
+
it 'returns invalid value if coercion returns a wrong type' do
|
762
|
+
get '/', int: 'lol'
|
763
|
+
|
764
|
+
expect(last_response.status).to eq(400)
|
765
|
+
expect(last_response.body).to eq('int is invalid')
|
766
|
+
end
|
767
|
+
end
|
768
|
+
|
481
769
|
it 'must be supplied with :type or :coerce' do
|
482
770
|
expect do
|
483
771
|
subject.params do
|
@@ -298,4 +298,174 @@ describe Grape::Validations::DefaultValidator do
|
|
298
298
|
end
|
299
299
|
end
|
300
300
|
end
|
301
|
+
|
302
|
+
context 'optional with nil as value' do
|
303
|
+
subject do
|
304
|
+
Class.new(Grape::API) do
|
305
|
+
default_format :json
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def app
|
310
|
+
subject
|
311
|
+
end
|
312
|
+
|
313
|
+
context 'primitive types' do
|
314
|
+
[
|
315
|
+
[Integer, 0],
|
316
|
+
[Integer, 42],
|
317
|
+
[Float, 0.0],
|
318
|
+
[Float, 4.2],
|
319
|
+
[BigDecimal, 0.0],
|
320
|
+
[BigDecimal, 4.2],
|
321
|
+
[Numeric, 0],
|
322
|
+
[Numeric, 42],
|
323
|
+
[Date, Date.today],
|
324
|
+
[DateTime, DateTime.now],
|
325
|
+
[Time, Time.now],
|
326
|
+
[Time, Time.at(0)],
|
327
|
+
[Grape::API::Boolean, false],
|
328
|
+
[String, ''],
|
329
|
+
[String, 'non-empty-string'],
|
330
|
+
[Symbol, :symbol],
|
331
|
+
[TrueClass, true],
|
332
|
+
[FalseClass, false]
|
333
|
+
].each do |type, default|
|
334
|
+
it 'respects the default value' do
|
335
|
+
subject.params do
|
336
|
+
optional :param, type: type, default: default
|
337
|
+
end
|
338
|
+
subject.get '/default_value' do
|
339
|
+
params[:param]
|
340
|
+
end
|
341
|
+
|
342
|
+
get '/default_value', param: nil
|
343
|
+
expect(last_response.status).to eq(200)
|
344
|
+
expect(last_response.body).to eq(default.to_json)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
context 'structures types' do
|
350
|
+
[
|
351
|
+
[Hash, {}],
|
352
|
+
[Hash, { test: 'non-empty' }],
|
353
|
+
[Array, []],
|
354
|
+
[Array, ['non-empty']],
|
355
|
+
[Array[Integer], []],
|
356
|
+
[Set, []],
|
357
|
+
[Set, [1]]
|
358
|
+
].each do |type, default|
|
359
|
+
it 'respects the default value' do
|
360
|
+
subject.params do
|
361
|
+
optional :param, type: type, default: default
|
362
|
+
end
|
363
|
+
subject.get '/default_value' do
|
364
|
+
params[:param]
|
365
|
+
end
|
366
|
+
|
367
|
+
get '/default_value', param: nil
|
368
|
+
expect(last_response.status).to eq(200)
|
369
|
+
expect(last_response.body).to eq(default.to_json)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
context 'special types' do
|
375
|
+
[
|
376
|
+
[JSON, ''],
|
377
|
+
[JSON, { test: 'non-empty-string' }.to_json],
|
378
|
+
[Array[JSON], []],
|
379
|
+
[Array[JSON], [{ test: 'non-empty-string' }.to_json]],
|
380
|
+
[::File, ''],
|
381
|
+
[::File, { test: 'non-empty-string' }.to_json],
|
382
|
+
[Rack::Multipart::UploadedFile, ''],
|
383
|
+
[Rack::Multipart::UploadedFile, { test: 'non-empty-string' }.to_json]
|
384
|
+
].each do |type, default|
|
385
|
+
it 'respects the default value' do
|
386
|
+
subject.params do
|
387
|
+
optional :param, type: type, default: default
|
388
|
+
end
|
389
|
+
subject.get '/default_value' do
|
390
|
+
params[:param]
|
391
|
+
end
|
392
|
+
|
393
|
+
get '/default_value', param: nil
|
394
|
+
expect(last_response.status).to eq(200)
|
395
|
+
expect(last_response.body).to eq(default.to_json)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
context 'variant-member-type collections' do
|
401
|
+
[
|
402
|
+
[Array[Integer, String], [0, '']],
|
403
|
+
[Array[Integer, String], [42, 'non-empty-string']],
|
404
|
+
[[Integer, String, Array[Integer, String]], [0, '', [0, '']]],
|
405
|
+
[[Integer, String, Array[Integer, String]], [42, 'non-empty-string', [42, 'non-empty-string']]]
|
406
|
+
].each do |type, default|
|
407
|
+
it 'respects the default value' do
|
408
|
+
subject.params do
|
409
|
+
optional :param, type: type, default: default
|
410
|
+
end
|
411
|
+
subject.get '/default_value' do
|
412
|
+
params[:param]
|
413
|
+
end
|
414
|
+
|
415
|
+
get '/default_value', param: nil
|
416
|
+
expect(last_response.status).to eq(200)
|
417
|
+
expect(last_response.body).to eq(default.to_json)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
context 'array with default values and given conditions' do
|
424
|
+
subject do
|
425
|
+
Class.new(Grape::API) do
|
426
|
+
default_format :json
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
def app
|
431
|
+
subject
|
432
|
+
end
|
433
|
+
|
434
|
+
it 'applies the default values only if the conditions are met' do
|
435
|
+
subject.params do
|
436
|
+
requires :ary, type: Array do
|
437
|
+
requires :has_value, type: Grape::API::Boolean
|
438
|
+
given has_value: ->(has_value) { has_value } do
|
439
|
+
optional :type, type: String, values: %w[str int], default: 'str'
|
440
|
+
given type: ->(type) { type == 'str' } do
|
441
|
+
optional :str, type: String, default: 'a'
|
442
|
+
end
|
443
|
+
given type: ->(type) { type == 'int' } do
|
444
|
+
optional :int, type: Integer, default: 1
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
subject.post('/nested_given_and_default') { declared(self.params) }
|
450
|
+
|
451
|
+
params = {
|
452
|
+
ary: [
|
453
|
+
{ has_value: false },
|
454
|
+
{ has_value: true, type: 'int', int: 123 },
|
455
|
+
{ has_value: true, type: 'str', str: 'b' }
|
456
|
+
]
|
457
|
+
}
|
458
|
+
expected = {
|
459
|
+
'ary' => [
|
460
|
+
{ 'has_value' => false, 'type' => nil, 'int' => nil, 'str' => nil },
|
461
|
+
{ 'has_value' => true, 'type' => 'int', 'int' => 123, 'str' => nil },
|
462
|
+
{ 'has_value' => true, 'type' => 'str', 'int' => nil, 'str' => 'b' }
|
463
|
+
]
|
464
|
+
}
|
465
|
+
|
466
|
+
post '/nested_given_and_default', params
|
467
|
+
expect(last_response.status).to eq(201)
|
468
|
+
expect(JSON.parse(last_response.body)).to eq(expected)
|
469
|
+
end
|
470
|
+
end
|
301
471
|
end
|