grape 1.3.3 → 1.6.2
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 +111 -2
- data/CONTRIBUTING.md +2 -1
- data/README.md +135 -23
- data/UPGRADING.md +237 -46
- data/grape.gemspec +5 -5
- data/lib/grape/api/instance.rb +34 -42
- data/lib/grape/api.rb +21 -16
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dsl/callbacks.rb +1 -1
- data/lib/grape/dsl/desc.rb +3 -5
- data/lib/grape/dsl/headers.rb +5 -2
- data/lib/grape/dsl/helpers.rb +8 -5
- data/lib/grape/dsl/inside_route.rb +72 -53
- data/lib/grape/dsl/middleware.rb +4 -4
- data/lib/grape/dsl/parameters.rb +11 -7
- data/lib/grape/dsl/request_response.rb +9 -6
- data/lib/grape/dsl/routing.rb +8 -9
- data/lib/grape/dsl/settings.rb +5 -5
- data/lib/grape/dsl/validations.rb +18 -1
- data/lib/grape/eager_load.rb +1 -1
- data/lib/grape/endpoint.rb +29 -42
- data/lib/grape/error_formatter/json.rb +2 -6
- data/lib/grape/error_formatter/xml.rb +2 -6
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/validation.rb +2 -3
- data/lib/grape/exceptions/validation_errors.rb +1 -1
- data/lib/grape/formatter/json.rb +1 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -1
- data/lib/grape/formatter/xml.rb +1 -0
- data/lib/grape/locale/en.yml +1 -1
- data/lib/grape/middleware/auth/base.rb +3 -3
- data/lib/grape/middleware/auth/dsl.rb +7 -1
- data/lib/grape/middleware/base.rb +6 -3
- data/lib/grape/middleware/error.rb +11 -13
- data/lib/grape/middleware/formatter.rb +7 -7
- data/lib/grape/middleware/stack.rb +10 -3
- data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
- data/lib/grape/middleware/versioner/header.rb +6 -4
- data/lib/grape/middleware/versioner/param.rb +1 -0
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
- data/lib/grape/middleware/versioner/path.rb +2 -0
- data/lib/grape/parser/json.rb +1 -1
- data/lib/grape/parser/xml.rb +1 -1
- data/lib/grape/path.rb +1 -0
- data/lib/grape/request.rb +4 -1
- data/lib/grape/router/attribute_translator.rb +3 -3
- data/lib/grape/router/pattern.rb +1 -1
- data/lib/grape/router/route.rb +2 -2
- data/lib/grape/router.rb +31 -30
- 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 +2 -2
- data/lib/grape/util/inheritable_setting.rb +1 -3
- data/lib/grape/util/lazy_value.rb +4 -2
- data/lib/grape/util/strict_hash_configuration.rb +1 -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 +97 -62
- data/lib/grape/validations/single_attribute_iterator.rb +1 -1
- data/lib/grape/validations/types/custom_type_coercer.rb +16 -3
- data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
- data/lib/grape/validations/types/invalid_value.rb +24 -0
- data/lib/grape/validations/types/json.rb +2 -1
- data/lib/grape/validations/types/primitive_coercer.rb +4 -5
- data/lib/grape/validations/types.rb +1 -4
- data/lib/grape/validations/validator_factory.rb +1 -1
- data/lib/grape/validations/validators/all_or_none.rb +8 -5
- data/lib/grape/validations/validators/allow_blank.rb +9 -7
- data/lib/grape/validations/validators/as.rb +6 -8
- data/lib/grape/validations/validators/at_least_one_of.rb +7 -4
- data/lib/grape/validations/validators/base.rb +74 -69
- data/lib/grape/validations/validators/coerce.rb +63 -76
- data/lib/grape/validations/validators/default.rb +36 -34
- data/lib/grape/validations/validators/exactly_one_of.rb +9 -6
- data/lib/grape/validations/validators/except_values.rb +13 -11
- data/lib/grape/validations/validators/multiple_params_base.rb +24 -19
- data/lib/grape/validations/validators/mutual_exclusion.rb +8 -5
- data/lib/grape/validations/validators/presence.rb +7 -4
- data/lib/grape/validations/validators/regexp.rb +8 -5
- data/lib/grape/validations/validators/same_as.rb +18 -15
- data/lib/grape/validations/validators/values.rb +61 -56
- data/lib/grape/validations.rb +6 -0
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +7 -3
- data/spec/grape/api/custom_validations_spec.rb +77 -45
- data/spec/grape/api/deeply_included_options_spec.rb +3 -3
- data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +1 -1
- data/spec/grape/api/routes_with_requirements_spec.rb +8 -8
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
- data/spec/grape/api_remount_spec.rb +25 -19
- data/spec/grape/api_spec.rb +576 -211
- data/spec/grape/dsl/callbacks_spec.rb +2 -1
- data/spec/grape/dsl/headers_spec.rb +39 -9
- data/spec/grape/dsl/helpers_spec.rb +3 -2
- data/spec/grape/dsl/inside_route_spec.rb +185 -34
- data/spec/grape/dsl/logger_spec.rb +16 -18
- data/spec/grape/dsl/middleware_spec.rb +2 -1
- data/spec/grape/dsl/parameters_spec.rb +2 -0
- data/spec/grape/dsl/request_response_spec.rb +1 -0
- data/spec/grape/dsl/routing_spec.rb +10 -7
- data/spec/grape/endpoint/declared_spec.rb +848 -0
- data/spec/grape/endpoint_spec.rb +77 -589
- data/spec/grape/entity_spec.rb +29 -23
- data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
- data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
- data/spec/grape/exceptions/validation_spec.rb +5 -3
- data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
- data/spec/grape/integration/rack_sendfile_spec.rb +13 -9
- data/spec/grape/loading_spec.rb +8 -8
- data/spec/grape/middleware/auth/dsl_spec.rb +15 -6
- data/spec/grape/middleware/auth/strategies_spec.rb +61 -21
- data/spec/grape/middleware/base_spec.rb +24 -15
- data/spec/grape/middleware/error_spec.rb +3 -3
- data/spec/grape/middleware/exception_spec.rb +111 -161
- data/spec/grape/middleware/formatter_spec.rb +28 -7
- data/spec/grape/middleware/globals_spec.rb +7 -4
- data/spec/grape/middleware/stack_spec.rb +15 -12
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
- data/spec/grape/middleware/versioner/header_spec.rb +14 -13
- data/spec/grape/middleware/versioner/param_spec.rb +7 -1
- data/spec/grape/middleware/versioner/path_spec.rb +5 -1
- data/spec/grape/middleware/versioner_spec.rb +1 -1
- data/spec/grape/parser_spec.rb +4 -0
- data/spec/grape/path_spec.rb +52 -52
- data/spec/grape/presenters/presenter_spec.rb +7 -6
- data/spec/grape/request_spec.rb +6 -4
- data/spec/grape/util/inheritable_setting_spec.rb +7 -7
- data/spec/grape/util/inheritable_values_spec.rb +3 -2
- data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
- data/spec/grape/util/stackable_values_spec.rb +7 -5
- data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +14 -3
- data/spec/grape/validations/params_scope_spec.rb +72 -10
- data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -6
- data/spec/grape/validations/types/primitive_coercer_spec.rb +63 -7
- data/spec/grape/validations/types_spec.rb +8 -8
- data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
- data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
- data/spec/grape/validations/validators/coerce_spec.rb +248 -33
- data/spec/grape/validations/validators/default_spec.rb +121 -78
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
- data/spec/grape/validations/validators/except_values_spec.rb +4 -3
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
- data/spec/grape/validations/validators/presence_spec.rb +16 -1
- data/spec/grape/validations/validators/regexp_spec.rb +25 -31
- data/spec/grape/validations/validators/same_as_spec.rb +14 -20
- data/spec/grape/validations/validators/values_spec.rb +183 -178
- data/spec/grape/validations_spec.rb +342 -29
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/integration/multi_json/json_spec.rb +1 -1
- data/spec/integration/multi_xml/xml_spec.rb +1 -1
- data/spec/shared/versioning_examples.rb +32 -29
- data/spec/spec_helper.rb +12 -12
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- data/spec/support/chunks.rb +14 -0
- data/spec/support/versioned_helpers.rb +4 -6
- metadata +110 -102
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe Grape::Validations::CoerceValidator do
|
5
|
+
describe Grape::Validations::Validators::CoerceValidator do
|
6
6
|
subject do
|
7
7
|
Class.new(Grape::API)
|
8
8
|
end
|
@@ -23,7 +23,7 @@ describe Grape::Validations::CoerceValidator do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
context 'i18n' do
|
26
|
-
after
|
26
|
+
after do
|
27
27
|
I18n.available_locales = %i[en]
|
28
28
|
I18n.locale = :en
|
29
29
|
I18n.default_locale = :en
|
@@ -31,9 +31,9 @@ describe Grape::Validations::CoerceValidator do
|
|
31
31
|
|
32
32
|
it 'i18n error on malformed input' do
|
33
33
|
I18n.available_locales = %i[en zh-CN]
|
34
|
-
I18n.load_path << File.expand_path('
|
34
|
+
I18n.load_path << File.expand_path('zh-CN.yml', __dir__)
|
35
35
|
I18n.reload!
|
36
|
-
I18n.locale = 'zh-CN'
|
36
|
+
I18n.locale = :'zh-CN'
|
37
37
|
subject.params do
|
38
38
|
requires :age, type: Integer
|
39
39
|
end
|
@@ -48,7 +48,7 @@ describe Grape::Validations::CoerceValidator do
|
|
48
48
|
|
49
49
|
it 'gives an english fallback error when default locale message is blank' do
|
50
50
|
I18n.available_locales = %i[en pt-BR]
|
51
|
-
I18n.locale = 'pt-BR'
|
51
|
+
I18n.locale = :'pt-BR'
|
52
52
|
subject.params do
|
53
53
|
requires :age, type: Integer
|
54
54
|
end
|
@@ -83,10 +83,11 @@ describe Grape::Validations::CoerceValidator do
|
|
83
83
|
context 'on custom coercion rules' do
|
84
84
|
before do
|
85
85
|
subject.params do
|
86
|
-
requires :a, types: { value: [Boolean, String], message: 'type cast is invalid' }, coerce_with: (lambda do |val|
|
87
|
-
|
86
|
+
requires :a, types: { value: [Grape::API::Boolean, String], message: 'type cast is invalid' }, coerce_with: (lambda do |val|
|
87
|
+
case val
|
88
|
+
when 'yup'
|
88
89
|
true
|
89
|
-
|
90
|
+
when 'false'
|
90
91
|
0
|
91
92
|
else
|
92
93
|
val
|
@@ -170,9 +171,9 @@ describe Grape::Validations::CoerceValidator do
|
|
170
171
|
expect(last_response.body).to eq('BigDecimal 45.1')
|
171
172
|
end
|
172
173
|
|
173
|
-
it 'Boolean' do
|
174
|
+
it 'Grape::API::Boolean' do
|
174
175
|
subject.params do
|
175
|
-
requires :boolean, type: Boolean
|
176
|
+
requires :boolean, type: Grape::API::Boolean
|
176
177
|
end
|
177
178
|
subject.post '/boolean' do
|
178
179
|
params[:boolean]
|
@@ -227,23 +228,51 @@ describe Grape::Validations::CoerceValidator do
|
|
227
228
|
expect(last_response.body).to eq('NilClass')
|
228
229
|
end
|
229
230
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
231
|
+
context 'a custom type' do
|
232
|
+
it 'coerces the given value' do
|
233
|
+
subject.params do
|
234
|
+
requires :uri, coerce: SecureURIOnly
|
235
|
+
end
|
236
|
+
subject.get '/secure_uri' do
|
237
|
+
params[:uri].class
|
238
|
+
end
|
239
|
+
|
240
|
+
get 'secure_uri', uri: 'https://www.example.com'
|
241
|
+
|
242
|
+
expect(last_response.status).to eq(200)
|
243
|
+
expect(last_response.body).to eq('URI::HTTPS')
|
244
|
+
|
245
|
+
get 'secure_uri', uri: 'http://www.example.com'
|
246
|
+
|
247
|
+
expect(last_response.status).to eq(400)
|
248
|
+
expect(last_response.body).to eq('uri is invalid')
|
236
249
|
end
|
237
250
|
|
238
|
-
|
251
|
+
context 'returning the InvalidValue instance when invalid' do
|
252
|
+
let(:custom_type) do
|
253
|
+
Class.new do
|
254
|
+
def self.parse(_val)
|
255
|
+
Grape::Types::InvalidValue.new('must be unique')
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
239
259
|
|
240
|
-
|
241
|
-
|
260
|
+
it 'uses a custom message added to the invalid value' do
|
261
|
+
type = custom_type
|
242
262
|
|
243
|
-
|
263
|
+
subject.params do
|
264
|
+
requires :name, type: type
|
265
|
+
end
|
266
|
+
subject.get '/whatever' do
|
267
|
+
params[:name].class
|
268
|
+
end
|
244
269
|
|
245
|
-
|
246
|
-
|
270
|
+
get 'whatever', name: 'Bob'
|
271
|
+
|
272
|
+
expect(last_response.status).to eq(400)
|
273
|
+
expect(last_response.body).to eq('name must be unique')
|
274
|
+
end
|
275
|
+
end
|
247
276
|
end
|
248
277
|
|
249
278
|
context 'Array' do
|
@@ -341,9 +370,9 @@ describe Grape::Validations::CoerceValidator do
|
|
341
370
|
end
|
342
371
|
end
|
343
372
|
|
344
|
-
it 'Boolean' do
|
373
|
+
it 'Grape::API::Boolean' do
|
345
374
|
subject.params do
|
346
|
-
requires :boolean, type: Boolean
|
375
|
+
requires :boolean, type: Grape::API::Boolean
|
347
376
|
end
|
348
377
|
subject.get '/boolean' do
|
349
378
|
params[:boolean].class
|
@@ -497,6 +526,92 @@ describe Grape::Validations::CoerceValidator do
|
|
497
526
|
end
|
498
527
|
end
|
499
528
|
end
|
529
|
+
|
530
|
+
context 'empty string' do
|
531
|
+
context 'primitive types' do
|
532
|
+
(Grape::Validations::Types::PRIMITIVES - [String]).each do |type|
|
533
|
+
it "is coerced to nil for type #{type}" do
|
534
|
+
subject.params do
|
535
|
+
requires :param, type: type
|
536
|
+
end
|
537
|
+
subject.get '/empty_string' do
|
538
|
+
params[:param].class
|
539
|
+
end
|
540
|
+
|
541
|
+
get '/empty_string', param: ''
|
542
|
+
expect(last_response.status).to eq(200)
|
543
|
+
expect(last_response.body).to eq('NilClass')
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
it 'is not coerced to nil for type String' do
|
548
|
+
subject.params do
|
549
|
+
requires :param, type: String
|
550
|
+
end
|
551
|
+
subject.get '/empty_string' do
|
552
|
+
params[:param].class
|
553
|
+
end
|
554
|
+
|
555
|
+
get '/empty_string', param: ''
|
556
|
+
expect(last_response.status).to eq(200)
|
557
|
+
expect(last_response.body).to eq('String')
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
context 'structures types' do
|
562
|
+
(Grape::Validations::Types::STRUCTURES - [Hash]).each do |type|
|
563
|
+
it "is coerced to nil for type #{type}" do
|
564
|
+
subject.params do
|
565
|
+
requires :param, type: type
|
566
|
+
end
|
567
|
+
subject.get '/empty_string' do
|
568
|
+
params[:param].class
|
569
|
+
end
|
570
|
+
|
571
|
+
get '/empty_string', param: ''
|
572
|
+
expect(last_response.status).to eq(200)
|
573
|
+
expect(last_response.body).to eq('NilClass')
|
574
|
+
end
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
context 'special types' do
|
579
|
+
(Grape::Validations::Types::SPECIAL.keys - [File, Rack::Multipart::UploadedFile]).each do |type|
|
580
|
+
it "is coerced to nil for type #{type}" do
|
581
|
+
subject.params do
|
582
|
+
requires :param, type: type
|
583
|
+
end
|
584
|
+
subject.get '/empty_string' do
|
585
|
+
params[:param].class
|
586
|
+
end
|
587
|
+
|
588
|
+
get '/empty_string', param: ''
|
589
|
+
expect(last_response.status).to eq(200)
|
590
|
+
expect(last_response.body).to eq('NilClass')
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
context 'variant-member-type collections' do
|
595
|
+
[
|
596
|
+
Array[Integer, String],
|
597
|
+
[Integer, String, Array[Integer, String]]
|
598
|
+
].each do |type|
|
599
|
+
it "is coerced to nil for type #{type}" do
|
600
|
+
subject.params do
|
601
|
+
requires :param, type: type
|
602
|
+
end
|
603
|
+
subject.get '/empty_string' do
|
604
|
+
params[:param].class
|
605
|
+
end
|
606
|
+
|
607
|
+
get '/empty_string', param: ''
|
608
|
+
expect(last_response.status).to eq(200)
|
609
|
+
expect(last_response.body).to eq('NilClass')
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
end
|
614
|
+
end
|
500
615
|
end
|
501
616
|
|
502
617
|
context 'using coerce_with' do
|
@@ -534,6 +649,30 @@ describe Grape::Validations::CoerceValidator do
|
|
534
649
|
expect(JSON.parse(last_response.body)).to eq(%w[a b c d])
|
535
650
|
end
|
536
651
|
|
652
|
+
it 'parses parameters with Array[Array[String]] type and coerce_with' do
|
653
|
+
subject.params do
|
654
|
+
requires :values, type: Array[Array[String]], coerce_with: ->(val) { val.is_a?(String) ? [val.split(',').map(&:strip)] : val }
|
655
|
+
end
|
656
|
+
subject.post '/coerce_nested_strings' do
|
657
|
+
params[:values]
|
658
|
+
end
|
659
|
+
|
660
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: 'a,b,c,d'), 'CONTENT_TYPE' => 'application/json'
|
661
|
+
expect(last_response.status).to eq(201)
|
662
|
+
expect(JSON.parse(last_response.body)).to eq([%w[a b c d]])
|
663
|
+
|
664
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: [%w[a c], %w[b]]), 'CONTENT_TYPE' => 'application/json'
|
665
|
+
expect(last_response.status).to eq(201)
|
666
|
+
expect(JSON.parse(last_response.body)).to eq([%w[a c], %w[b]])
|
667
|
+
|
668
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: [[]]), 'CONTENT_TYPE' => 'application/json'
|
669
|
+
expect(last_response.status).to eq(201)
|
670
|
+
expect(JSON.parse(last_response.body)).to eq([[]])
|
671
|
+
|
672
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: [['a', { bar: 0 }], ['b']]), 'CONTENT_TYPE' => 'application/json'
|
673
|
+
expect(last_response.status).to eq(400)
|
674
|
+
end
|
675
|
+
|
537
676
|
it 'parses parameters with Array[Integer] type' do
|
538
677
|
subject.params do
|
539
678
|
requires :values, type: Array[Integer], coerce_with: ->(val) { val.split(/\s+/).map(&:to_i) }
|
@@ -568,6 +707,44 @@ describe Grape::Validations::CoerceValidator do
|
|
568
707
|
expect(JSON.parse(last_response.body)).to eq([1, 1, 1, 1])
|
569
708
|
end
|
570
709
|
|
710
|
+
context 'Array type and coerce_with should' do
|
711
|
+
before do
|
712
|
+
subject.params do
|
713
|
+
optional :arr, type: Array, coerce_with: (lambda do |val|
|
714
|
+
if val.nil?
|
715
|
+
[]
|
716
|
+
else
|
717
|
+
val
|
718
|
+
end
|
719
|
+
end)
|
720
|
+
end
|
721
|
+
subject.get '/' do
|
722
|
+
params[:arr].class.to_s
|
723
|
+
end
|
724
|
+
end
|
725
|
+
|
726
|
+
it 'coerce nil value to array' do
|
727
|
+
get '/', arr: nil
|
728
|
+
|
729
|
+
expect(last_response.status).to eq(200)
|
730
|
+
expect(last_response.body).to eq('Array')
|
731
|
+
end
|
732
|
+
|
733
|
+
it 'not coerce missing field' do
|
734
|
+
get '/'
|
735
|
+
|
736
|
+
expect(last_response.status).to eq(200)
|
737
|
+
expect(last_response.body).to eq('NilClass')
|
738
|
+
end
|
739
|
+
|
740
|
+
it 'coerce array as array' do
|
741
|
+
get '/', arr: []
|
742
|
+
|
743
|
+
expect(last_response.status).to eq(200)
|
744
|
+
expect(last_response.body).to eq('Array')
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
571
748
|
it 'uses parse where available' do
|
572
749
|
subject.params do
|
573
750
|
requires :ints, type: Array, coerce_with: JSON do
|
@@ -616,13 +793,52 @@ describe Grape::Validations::CoerceValidator do
|
|
616
793
|
expect(last_response.body).to eq('3')
|
617
794
|
end
|
618
795
|
|
796
|
+
context 'Integer type and coerce_with should' do
|
797
|
+
before do
|
798
|
+
subject.params do
|
799
|
+
optional :int, type: Integer, coerce_with: (lambda do |val|
|
800
|
+
if val.nil?
|
801
|
+
0
|
802
|
+
else
|
803
|
+
val.to_i
|
804
|
+
end
|
805
|
+
end)
|
806
|
+
end
|
807
|
+
subject.get '/' do
|
808
|
+
params[:int].class.to_s
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
it 'coerce nil value to integer' do
|
813
|
+
get '/', int: nil
|
814
|
+
|
815
|
+
expect(last_response.status).to eq(200)
|
816
|
+
expect(last_response.body).to eq('Integer')
|
817
|
+
end
|
818
|
+
|
819
|
+
it 'not coerce missing field' do
|
820
|
+
get '/'
|
821
|
+
|
822
|
+
expect(last_response.status).to eq(200)
|
823
|
+
expect(last_response.body).to eq('NilClass')
|
824
|
+
end
|
825
|
+
|
826
|
+
it 'coerce integer as integer' do
|
827
|
+
get '/', int: 1
|
828
|
+
|
829
|
+
expect(last_response.status).to eq(200)
|
830
|
+
expect(last_response.body).to eq('Integer')
|
831
|
+
end
|
832
|
+
end
|
833
|
+
|
619
834
|
context 'Integer type and coerce_with potentially returning nil' do
|
620
835
|
before do
|
621
836
|
subject.params do
|
622
837
|
requires :int, type: Integer, coerce_with: (lambda do |val|
|
623
|
-
|
838
|
+
case val
|
839
|
+
when '0'
|
624
840
|
nil
|
625
|
-
|
841
|
+
when /^-?\d+$/
|
626
842
|
val.to_i
|
627
843
|
else
|
628
844
|
val
|
@@ -802,11 +1018,9 @@ describe Grape::Validations::CoerceValidator do
|
|
802
1018
|
end
|
803
1019
|
|
804
1020
|
context 'multiple types' do
|
805
|
-
Boolean = Grape::API::Boolean
|
806
|
-
|
807
1021
|
it 'coerces to first possible type' do
|
808
1022
|
subject.params do
|
809
|
-
requires :a, types: [Boolean, Integer, String]
|
1023
|
+
requires :a, types: [Grape::API::Boolean, Integer, String]
|
810
1024
|
end
|
811
1025
|
subject.get '/' do
|
812
1026
|
params[:a].class.to_s
|
@@ -827,7 +1041,7 @@ describe Grape::Validations::CoerceValidator do
|
|
827
1041
|
|
828
1042
|
it 'fails when no coercion is possible' do
|
829
1043
|
subject.params do
|
830
|
-
requires :a, types: [Boolean, Integer]
|
1044
|
+
requires :a, types: [Grape::API::Boolean, Integer]
|
831
1045
|
end
|
832
1046
|
subject.get '/' do
|
833
1047
|
params[:a].class.to_s
|
@@ -986,10 +1200,11 @@ describe Grape::Validations::CoerceValidator do
|
|
986
1200
|
context 'custom coercion rules' do
|
987
1201
|
before do
|
988
1202
|
subject.params do
|
989
|
-
requires :a, types: [Boolean, String], coerce_with: (lambda do |val|
|
990
|
-
|
1203
|
+
requires :a, types: [Grape::API::Boolean, String], coerce_with: (lambda do |val|
|
1204
|
+
case val
|
1205
|
+
when 'yup'
|
991
1206
|
true
|
992
|
-
|
1207
|
+
when 'false'
|
993
1208
|
0
|
994
1209
|
else
|
995
1210
|
val
|
@@ -2,104 +2,98 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe Grape::Validations::DefaultValidator do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
5
|
+
describe Grape::Validations::Validators::DefaultValidator do
|
6
|
+
let_it_be(:app) do
|
7
|
+
Class.new(Grape::API) do
|
8
|
+
default_format :json
|
9
|
+
|
10
|
+
params do
|
11
|
+
optional :id
|
12
|
+
optional :type, default: 'default-type'
|
13
|
+
end
|
14
|
+
get '/' do
|
15
|
+
{ id: params[:id], type: params[:type] }
|
16
|
+
end
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
params do
|
19
|
+
optional :type1, default: 'default-type1'
|
20
|
+
optional :type2, default: 'default-type2'
|
21
|
+
end
|
22
|
+
get '/user' do
|
23
|
+
{ type1: params[:type1], type2: params[:type2] }
|
24
|
+
end
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
params do
|
27
|
+
requires :id
|
28
|
+
optional :type1, default: 'default-type1'
|
29
|
+
optional :type2, default: 'default-type2'
|
30
|
+
end
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
get '/message' do
|
33
|
+
{ id: params[:id], type1: params[:type1], type2: params[:type2] }
|
34
|
+
end
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
36
|
+
params do
|
37
|
+
optional :random, default: -> { Random.rand }
|
38
|
+
optional :not_random, default: Random.rand
|
39
|
+
end
|
40
|
+
get '/numbers' do
|
41
|
+
{ random_number: params[:random], non_random_number: params[:non_random_number] }
|
42
|
+
end
|
44
43
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
51
|
-
get '/array' do
|
52
|
-
{ array: params[:array] }
|
44
|
+
params do
|
45
|
+
optional :array, type: Array do
|
46
|
+
requires :name
|
47
|
+
optional :with_default, default: 'default'
|
53
48
|
end
|
49
|
+
end
|
50
|
+
get '/array' do
|
51
|
+
{ array: params[:array] }
|
52
|
+
end
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
end
|
62
|
-
get '/optional_array' do
|
63
|
-
{ thing1: params[:thing1] }
|
54
|
+
params do
|
55
|
+
requires :thing1
|
56
|
+
optional :more_things, type: Array do
|
57
|
+
requires :nested_thing
|
58
|
+
requires :other_thing, default: 1
|
64
59
|
end
|
60
|
+
end
|
61
|
+
get '/optional_array' do
|
62
|
+
{ thing1: params[:thing1] }
|
63
|
+
end
|
65
64
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end
|
65
|
+
params do
|
66
|
+
requires :root, type: Hash do
|
67
|
+
optional :some_things, type: Array do
|
68
|
+
requires :foo
|
69
|
+
optional :options, type: Array do
|
70
|
+
requires :name, type: String
|
71
|
+
requires :value, type: String
|
74
72
|
end
|
75
73
|
end
|
76
74
|
end
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
end
|
76
|
+
get '/nested_optional_array' do
|
77
|
+
{ root: params[:root] }
|
78
|
+
end
|
80
79
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
80
|
+
params do
|
81
|
+
requires :root, type: Hash do
|
82
|
+
optional :some_things, type: Array do
|
83
|
+
requires :foo
|
84
|
+
optional :options, type: Array do
|
85
|
+
optional :name, type: String
|
86
|
+
optional :value, type: String
|
89
87
|
end
|
90
88
|
end
|
91
89
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
90
|
+
end
|
91
|
+
get '/another_nested_optional_array' do
|
92
|
+
{ root: params[:root] }
|
95
93
|
end
|
96
94
|
end
|
97
95
|
end
|
98
96
|
|
99
|
-
def app
|
100
|
-
ValidationsSpec::DefaultValidatorSpec::API
|
101
|
-
end
|
102
|
-
|
103
97
|
it 'lets you leave required values nested inside an optional blank' do
|
104
98
|
get '/optional_array', thing1: 'stuff'
|
105
99
|
expect(last_response.status).to eq(200)
|
@@ -419,4 +413,53 @@ describe Grape::Validations::DefaultValidator do
|
|
419
413
|
end
|
420
414
|
end
|
421
415
|
end
|
416
|
+
|
417
|
+
context 'array with default values and given conditions' do
|
418
|
+
subject do
|
419
|
+
Class.new(Grape::API) do
|
420
|
+
default_format :json
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
def app
|
425
|
+
subject
|
426
|
+
end
|
427
|
+
|
428
|
+
it 'applies the default values only if the conditions are met' do
|
429
|
+
subject.params do
|
430
|
+
requires :ary, type: Array do
|
431
|
+
requires :has_value, type: Grape::API::Boolean
|
432
|
+
given has_value: ->(has_value) { has_value } do
|
433
|
+
optional :type, type: String, values: %w[str int], default: 'str'
|
434
|
+
given type: ->(type) { type == 'str' } do
|
435
|
+
optional :str, type: String, default: 'a'
|
436
|
+
end
|
437
|
+
given type: ->(type) { type == 'int' } do
|
438
|
+
optional :int, type: Integer, default: 1
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
subject.post('/nested_given_and_default') { declared(self.params) }
|
444
|
+
|
445
|
+
params = {
|
446
|
+
ary: [
|
447
|
+
{ has_value: false },
|
448
|
+
{ has_value: true, type: 'int', int: 123 },
|
449
|
+
{ has_value: true, type: 'str', str: 'b' }
|
450
|
+
]
|
451
|
+
}
|
452
|
+
expected = {
|
453
|
+
'ary' => [
|
454
|
+
{ 'has_value' => false, 'type' => nil, 'int' => nil, 'str' => nil },
|
455
|
+
{ 'has_value' => true, 'type' => 'int', 'int' => 123, 'str' => nil },
|
456
|
+
{ 'has_value' => true, 'type' => 'str', 'int' => nil, 'str' => 'b' }
|
457
|
+
]
|
458
|
+
}
|
459
|
+
|
460
|
+
post '/nested_given_and_default', params
|
461
|
+
expect(last_response.status).to eq(201)
|
462
|
+
expect(JSON.parse(last_response.body)).to eq(expected)
|
463
|
+
end
|
464
|
+
end
|
422
465
|
end
|