grape 1.1.0 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +128 -43
- data/LICENSE +1 -1
- data/README.md +394 -47
- data/UPGRADING.md +111 -0
- data/grape.gemspec +3 -1
- data/lib/grape.rb +98 -66
- data/lib/grape/api.rb +136 -175
- data/lib/grape/api/instance.rb +280 -0
- data/lib/grape/config.rb +32 -0
- data/lib/grape/dsl/callbacks.rb +20 -0
- data/lib/grape/dsl/desc.rb +39 -7
- data/lib/grape/dsl/inside_route.rb +12 -6
- data/lib/grape/dsl/middleware.rb +7 -0
- data/lib/grape/dsl/parameters.rb +9 -4
- data/lib/grape/dsl/routing.rb +5 -1
- data/lib/grape/dsl/validations.rb +4 -3
- data/lib/grape/eager_load.rb +18 -0
- data/lib/grape/endpoint.rb +42 -26
- data/lib/grape/error_formatter.rb +1 -1
- data/lib/grape/exceptions/base.rb +9 -1
- data/lib/grape/exceptions/invalid_response.rb +9 -0
- data/lib/grape/exceptions/validation_errors.rb +4 -2
- data/lib/grape/formatter.rb +1 -1
- data/lib/grape/locale/en.yml +2 -0
- data/lib/grape/middleware/auth/base.rb +2 -4
- data/lib/grape/middleware/base.rb +2 -0
- data/lib/grape/middleware/error.rb +9 -4
- data/lib/grape/middleware/helpers.rb +10 -0
- data/lib/grape/middleware/stack.rb +1 -1
- data/lib/grape/middleware/versioner/header.rb +4 -4
- data/lib/grape/parser.rb +1 -1
- data/lib/grape/request.rb +1 -1
- data/lib/grape/router/attribute_translator.rb +2 -0
- data/lib/grape/router/route.rb +2 -2
- data/lib/grape/util/base_inheritable.rb +34 -0
- data/lib/grape/util/endpoint_configuration.rb +6 -0
- data/lib/grape/util/inheritable_values.rb +5 -25
- data/lib/grape/util/lazy_block.rb +25 -0
- data/lib/grape/util/lazy_value.rb +95 -0
- data/lib/grape/util/reverse_stackable_values.rb +7 -36
- data/lib/grape/util/stackable_values.rb +19 -22
- data/lib/grape/validations/attributes_iterator.rb +5 -3
- data/lib/grape/validations/multiple_attributes_iterator.rb +11 -0
- data/lib/grape/validations/params_scope.rb +20 -14
- data/lib/grape/validations/single_attribute_iterator.rb +13 -0
- data/lib/grape/validations/types/custom_type_coercer.rb +1 -1
- data/lib/grape/validations/types/file.rb +1 -1
- data/lib/grape/validations/validator_factory.rb +6 -11
- data/lib/grape/validations/validators/all_or_none.rb +6 -13
- data/lib/grape/validations/validators/as.rb +2 -3
- data/lib/grape/validations/validators/at_least_one_of.rb +5 -13
- data/lib/grape/validations/validators/base.rb +11 -10
- data/lib/grape/validations/validators/coerce.rb +4 -0
- data/lib/grape/validations/validators/default.rb +1 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +6 -23
- data/lib/grape/validations/validators/multiple_params_base.rb +14 -10
- data/lib/grape/validations/validators/mutual_exclusion.rb +6 -18
- data/lib/grape/validations/validators/same_as.rb +23 -0
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/defines_boolean_in_params_spec.rb +37 -0
- data/spec/grape/api/routes_with_requirements_spec.rb +59 -0
- data/spec/grape/api_remount_spec.rb +466 -0
- data/spec/grape/api_spec.rb +379 -1
- data/spec/grape/config_spec.rb +17 -0
- data/spec/grape/dsl/desc_spec.rb +40 -16
- data/spec/grape/dsl/middleware_spec.rb +8 -0
- data/spec/grape/dsl/routing_spec.rb +10 -0
- data/spec/grape/endpoint_spec.rb +40 -4
- data/spec/grape/exceptions/base_spec.rb +65 -0
- data/spec/grape/exceptions/invalid_response_spec.rb +11 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +6 -4
- data/spec/grape/integration/rack_spec.rb +22 -6
- data/spec/grape/middleware/auth/dsl_spec.rb +3 -3
- data/spec/grape/middleware/base_spec.rb +8 -0
- data/spec/grape/middleware/exception_spec.rb +1 -1
- data/spec/grape/middleware/formatter_spec.rb +15 -5
- data/spec/grape/middleware/versioner/header_spec.rb +6 -0
- data/spec/grape/named_api_spec.rb +19 -0
- data/spec/grape/request_spec.rb +24 -0
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +29 -0
- data/spec/grape/validations/params_scope_spec.rb +184 -8
- data/spec/grape/validations/single_attribute_iterator_spec.rb +33 -0
- data/spec/grape/validations/validators/all_or_none_spec.rb +138 -30
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +173 -29
- data/spec/grape/validations/validators/coerce_spec.rb +10 -2
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +202 -38
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +184 -27
- data/spec/grape/validations/validators/same_as_spec.rb +63 -0
- data/spec/grape/validations_spec.rb +33 -21
- data/spec/spec_helper.rb +4 -1
- metadata +35 -23
- data/Appraisals +0 -32
- data/Dangerfile +0 -2
- data/Gemfile +0 -33
- data/Gemfile.lock +0 -231
- data/Guardfile +0 -10
- data/RELEASING.md +0 -111
- data/Rakefile +0 -25
- data/benchmark/simple.rb +0 -27
- data/benchmark/simple_with_type_coercer.rb +0 -22
- data/gemfiles/multi_json.gemfile +0 -35
- data/gemfiles/multi_xml.gemfile +0 -35
- data/gemfiles/rack_1.5.2.gemfile +0 -35
- data/gemfiles/rack_edge.gemfile +0 -35
- data/gemfiles/rails_3.gemfile +0 -36
- data/gemfiles/rails_4.gemfile +0 -35
- data/gemfiles/rails_5.gemfile +0 -35
- data/gemfiles/rails_edge.gemfile +0 -35
- data/pkg/grape-0.17.0.gem +0 -0
- data/pkg/grape-0.19.0.gem +0 -0
data/spec/grape/request_spec.rb
CHANGED
@@ -62,6 +62,30 @@ module Grape
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
+
describe 'when the param_builder is set to Hashie' do
|
66
|
+
before do
|
67
|
+
Grape.configure do |config|
|
68
|
+
config.param_builder = Grape::Extensions::Hashie::Mash::ParamBuilder
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
after do
|
73
|
+
Grape.config.reset
|
74
|
+
end
|
75
|
+
|
76
|
+
subject(:request_params) { Grape::Request.new(env, opts).params }
|
77
|
+
|
78
|
+
context 'when the API does not include a specific param builder' do
|
79
|
+
let(:opts) { {} }
|
80
|
+
it { is_expected.to be_a(Hashie::Mash) }
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when the API includes a specific param builder' do
|
84
|
+
let(:opts) { { build_params_with: Grape::Extensions::Hash::ParamBuilder } }
|
85
|
+
it { is_expected.to be_a(Hash) }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
65
89
|
describe '#headers' do
|
66
90
|
let(:options) do
|
67
91
|
default_options.merge(request_headers)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::Validations::MultipleAttributesIterator do
|
4
|
+
describe '#each' do
|
5
|
+
subject(:iterator) { described_class.new(validator, scope, params) }
|
6
|
+
let(:scope) { Grape::Validations::ParamsScope.new(api: Class.new(Grape::API)) }
|
7
|
+
let(:validator) { double(attrs: %i[first second third]) }
|
8
|
+
|
9
|
+
context 'when params is a hash' do
|
10
|
+
let(:params) do
|
11
|
+
{ first: 'string', second: 'string' }
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'yields the whole params hash without the list of attrs' do
|
15
|
+
expect { |b| iterator.each(&b) }.to yield_with_args(params)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when params is an array' do
|
20
|
+
let(:params) do
|
21
|
+
[{ first: 'string1', second: 'string1' }, { first: 'string2', second: 'string2' }]
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'yields each element of the array without the list of attrs' do
|
25
|
+
expect { |b| iterator.each(&b) }.to yield_successive_args(params[0], params[1])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -121,14 +121,14 @@ describe Grape::Validations::ParamsScope do
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
-
context 'param
|
124
|
+
context 'param renaming' do
|
125
125
|
it do
|
126
126
|
subject.params do
|
127
127
|
requires :foo, as: :bar
|
128
128
|
optional :super, as: :hiper
|
129
129
|
end
|
130
|
-
subject.get('/
|
131
|
-
get '/
|
130
|
+
subject.get('/renaming') { "#{declared(params)['bar']}-#{declared(params)['hiper']}" }
|
131
|
+
get '/renaming', foo: 'any', super: 'any2'
|
132
132
|
|
133
133
|
expect(last_response.status).to eq(200)
|
134
134
|
expect(last_response.body).to eq('any-any2')
|
@@ -138,8 +138,8 @@ describe Grape::Validations::ParamsScope do
|
|
138
138
|
subject.params do
|
139
139
|
requires :foo, as: :bar, type: String, coerce_with: ->(c) { c.strip }
|
140
140
|
end
|
141
|
-
subject.get('/
|
142
|
-
get '/
|
141
|
+
subject.get('/renaming-coerced') { "#{params['bar']}-#{params['foo']}" }
|
142
|
+
get '/renaming-coerced', foo: ' there we go '
|
143
143
|
|
144
144
|
expect(last_response.status).to eq(200)
|
145
145
|
expect(last_response.body).to eq('there we go-')
|
@@ -149,12 +149,35 @@ describe Grape::Validations::ParamsScope do
|
|
149
149
|
subject.params do
|
150
150
|
requires :foo, as: :bar, allow_blank: false
|
151
151
|
end
|
152
|
-
subject.get('/
|
153
|
-
get '/
|
152
|
+
subject.get('/renaming-not-blank') {}
|
153
|
+
get '/renaming-not-blank', foo: ''
|
154
154
|
|
155
155
|
expect(last_response.status).to eq(400)
|
156
156
|
expect(last_response.body).to eq('foo is empty')
|
157
157
|
end
|
158
|
+
|
159
|
+
it do
|
160
|
+
subject.params do
|
161
|
+
requires :foo, as: :bar, allow_blank: false
|
162
|
+
end
|
163
|
+
subject.get('/renaming-not-blank-with-value') {}
|
164
|
+
get '/renaming-not-blank-with-value', foo: 'any'
|
165
|
+
|
166
|
+
expect(last_response.status).to eq(200)
|
167
|
+
end
|
168
|
+
|
169
|
+
it do
|
170
|
+
subject.params do
|
171
|
+
requires :foo, as: :baz, type: Hash do
|
172
|
+
requires :bar, as: :qux
|
173
|
+
end
|
174
|
+
end
|
175
|
+
subject.get('/nested-renaming') { declared(params).to_json }
|
176
|
+
get '/nested-renaming', foo: { bar: 'any' }
|
177
|
+
|
178
|
+
expect(last_response.status).to eq(200)
|
179
|
+
expect(last_response.body).to eq('{"baz":{"qux":"any"}}')
|
180
|
+
end
|
158
181
|
end
|
159
182
|
|
160
183
|
context 'array without coerce type explicitly given' do
|
@@ -479,7 +502,50 @@ describe Grape::Validations::ParamsScope do
|
|
479
502
|
end.to_not raise_error
|
480
503
|
end
|
481
504
|
|
482
|
-
it '
|
505
|
+
it 'does not raise an error if when using nested given' do
|
506
|
+
expect do
|
507
|
+
subject.params do
|
508
|
+
optional :a, type: Hash do
|
509
|
+
requires :b
|
510
|
+
end
|
511
|
+
given :a do
|
512
|
+
requires :c
|
513
|
+
given :c do
|
514
|
+
requires :d
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end.to_not raise_error
|
519
|
+
end
|
520
|
+
|
521
|
+
it 'allows nested dependent parameters' do
|
522
|
+
subject.params do
|
523
|
+
optional :a
|
524
|
+
given a: ->(val) { val == 'a' } do
|
525
|
+
optional :b
|
526
|
+
given b: ->(val) { val == 'b' } do
|
527
|
+
optional :c
|
528
|
+
given c: ->(val) { val == 'c' } do
|
529
|
+
requires :d
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
subject.get('/') { declared(params).to_json }
|
535
|
+
|
536
|
+
get '/'
|
537
|
+
expect(last_response.status).to eq 200
|
538
|
+
|
539
|
+
get '/', a: 'a', b: 'b', c: 'c'
|
540
|
+
expect(last_response.status).to eq 400
|
541
|
+
expect(last_response.body).to eq 'd is missing'
|
542
|
+
|
543
|
+
get '/', a: 'a', b: 'b', c: 'c', d: 'd'
|
544
|
+
expect(last_response.status).to eq 200
|
545
|
+
expect(last_response.body).to eq({ a: 'a', b: 'b', c: 'c', d: 'd' }.to_json)
|
546
|
+
end
|
547
|
+
|
548
|
+
it 'allows renaming of dependent parameters' do
|
483
549
|
subject.params do
|
484
550
|
optional :a
|
485
551
|
given :a do
|
@@ -497,6 +563,34 @@ describe Grape::Validations::ParamsScope do
|
|
497
563
|
expect(body.keys).to_not include('b')
|
498
564
|
end
|
499
565
|
|
566
|
+
it 'allows renaming of dependent on parameter' do
|
567
|
+
subject.params do
|
568
|
+
optional :a, as: :b
|
569
|
+
given b: ->(val) { val == 'x' } do
|
570
|
+
requires :c
|
571
|
+
end
|
572
|
+
end
|
573
|
+
subject.get('/') { declared(params) }
|
574
|
+
|
575
|
+
get '/', a: 'x'
|
576
|
+
expect(last_response.status).to eq 400
|
577
|
+
expect(last_response.body).to eq 'c is missing'
|
578
|
+
|
579
|
+
get '/', a: 'y'
|
580
|
+
expect(last_response.status).to eq 200
|
581
|
+
end
|
582
|
+
|
583
|
+
it 'raises an error if the dependent parameter is not the renamed one' do
|
584
|
+
expect do
|
585
|
+
subject.params do
|
586
|
+
optional :a, as: :b
|
587
|
+
given :a do
|
588
|
+
requires :c
|
589
|
+
end
|
590
|
+
end
|
591
|
+
end.to raise_error(Grape::Exceptions::UnknownParameter)
|
592
|
+
end
|
593
|
+
|
500
594
|
it 'does not validate nested requires when given is false' do
|
501
595
|
subject.params do
|
502
596
|
requires :a, type: String, allow_blank: false, values: %w[x y z]
|
@@ -592,7 +686,53 @@ describe Grape::Validations::ParamsScope do
|
|
592
686
|
end
|
593
687
|
end
|
594
688
|
|
689
|
+
context 'default value in given block' do
|
690
|
+
before do
|
691
|
+
subject.params do
|
692
|
+
optional :a, values: %w[a b]
|
693
|
+
given a: ->(val) { val == 'a' } do
|
694
|
+
optional :b, default: 'default'
|
695
|
+
end
|
696
|
+
end
|
697
|
+
subject.get('/') { params.to_json }
|
698
|
+
end
|
699
|
+
|
700
|
+
context 'when dependency meets' do
|
701
|
+
it 'sets default value for dependent parameter' do
|
702
|
+
get '/', a: 'a'
|
703
|
+
expect(last_response.body).to eq({ a: 'a', b: 'default' }.to_json)
|
704
|
+
end
|
705
|
+
end
|
706
|
+
|
707
|
+
context 'when dependency does not meet' do
|
708
|
+
it 'does not set default value for dependent parameter' do
|
709
|
+
get '/', a: 'b'
|
710
|
+
expect(last_response.body).to eq({ a: 'b' }.to_json)
|
711
|
+
end
|
712
|
+
end
|
713
|
+
end
|
714
|
+
|
595
715
|
context 'when validations are dependent on a parameter within an array param' do
|
716
|
+
before do
|
717
|
+
subject.params do
|
718
|
+
requires :foos, type: Array do
|
719
|
+
optional :foo
|
720
|
+
given :foo do
|
721
|
+
requires :bar
|
722
|
+
end
|
723
|
+
end
|
724
|
+
end
|
725
|
+
subject.get('/test') { 'ok' }
|
726
|
+
end
|
727
|
+
|
728
|
+
it 'should pass none Hash params' do
|
729
|
+
get '/test', foos: ['']
|
730
|
+
expect(last_response.status).to eq(200)
|
731
|
+
expect(last_response.body).to eq('ok')
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
context 'when validations are dependent on a parameter within an array param within #declared(params).to_json' do
|
596
736
|
before do
|
597
737
|
subject.params do
|
598
738
|
requires :foos, type: Array do
|
@@ -948,4 +1088,40 @@ describe Grape::Validations::ParamsScope do
|
|
948
1088
|
end
|
949
1089
|
end
|
950
1090
|
end
|
1091
|
+
|
1092
|
+
context 'with exactly_one_of validation for optional parameters within an Hash param' do
|
1093
|
+
before do
|
1094
|
+
subject.params do
|
1095
|
+
optional :memo, type: Hash do
|
1096
|
+
optional :text, type: String
|
1097
|
+
optional :custom_body, type: Hash, coerce_with: JSON
|
1098
|
+
exactly_one_of :text, :custom_body
|
1099
|
+
end
|
1100
|
+
end
|
1101
|
+
subject.get('test')
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
context 'when correct data is provided' do
|
1105
|
+
it 'returns a successful response' do
|
1106
|
+
get 'test', memo: {}
|
1107
|
+
expect(last_response.status).to eq(200)
|
1108
|
+
|
1109
|
+
get 'test', memo: { text: 'HOGEHOGE' }
|
1110
|
+
expect(last_response.status).to eq(200)
|
1111
|
+
|
1112
|
+
get 'test', memo: { custom_body: '{ "xxx": "yyy" }' }
|
1113
|
+
expect(last_response.status).to eq(200)
|
1114
|
+
end
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
context 'when invalid data is provided' do
|
1118
|
+
it 'returns a failure response' do
|
1119
|
+
get 'test', memo: { text: 'HOGEHOGE', custom_body: '{ "xxx": "yyy" }' }
|
1120
|
+
expect(last_response.status).to eq(400)
|
1121
|
+
|
1122
|
+
get 'test', memo: '{ "custom_body": "HOGE" }'
|
1123
|
+
expect(last_response.status).to eq(400)
|
1124
|
+
end
|
1125
|
+
end
|
1126
|
+
end
|
951
1127
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::Validations::SingleAttributeIterator do
|
4
|
+
describe '#each' do
|
5
|
+
subject(:iterator) { described_class.new(validator, scope, params) }
|
6
|
+
let(:scope) { Grape::Validations::ParamsScope.new(api: Class.new(Grape::API)) }
|
7
|
+
let(:validator) { double(attrs: %i[first second third]) }
|
8
|
+
|
9
|
+
context 'when params is a hash' do
|
10
|
+
let(:params) do
|
11
|
+
{ first: 'string', second: 'string' }
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'yields params and every single attribute from the list' do
|
15
|
+
expect { |b| iterator.each(&b) }
|
16
|
+
.to yield_successive_args([params, :first], [params, :second], [params, :third])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when params is an array' do
|
21
|
+
let(:params) do
|
22
|
+
[{ first: 'string1', second: 'string1' }, { first: 'string2', second: 'string2' }]
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'yields every single attribute from the list for each of the array elements' do
|
26
|
+
expect { |b| iterator.each(&b) }.to yield_successive_args(
|
27
|
+
[params[0], :first], [params[0], :second], [params[0], :third],
|
28
|
+
[params[1], :first], [params[1], :second], [params[1], :third]
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -2,58 +2,166 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Grape::Validations::AllOrNoneOfValidator do
|
4
4
|
describe '#validate!' do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
subject(:validate) { post path, params }
|
6
|
+
|
7
|
+
module ValidationsSpec
|
8
|
+
module AllOrNoneOfValidatorSpec
|
9
|
+
class API < Grape::API
|
10
|
+
rescue_from Grape::Exceptions::ValidationErrors do |e|
|
11
|
+
error!(e.errors.transform_keys! { |key| key.join(',') }, 400)
|
12
|
+
end
|
13
|
+
|
14
|
+
params do
|
15
|
+
optional :beer, :wine, type: Boolean
|
16
|
+
all_or_none_of :beer, :wine
|
17
|
+
end
|
18
|
+
post do
|
19
|
+
end
|
20
|
+
|
21
|
+
params do
|
22
|
+
optional :beer, :wine, :other, type: Boolean
|
23
|
+
all_or_none_of :beer, :wine
|
24
|
+
end
|
25
|
+
post 'mixed-params' do
|
26
|
+
end
|
27
|
+
|
28
|
+
params do
|
29
|
+
optional :beer, :wine, type: Boolean
|
30
|
+
all_or_none_of :beer, :wine, message: 'choose all or none'
|
31
|
+
end
|
32
|
+
post '/custom-message' do
|
33
|
+
end
|
34
|
+
|
35
|
+
params do
|
36
|
+
requires :item, type: Hash do
|
37
|
+
optional :beer, :wine, type: Boolean
|
38
|
+
all_or_none_of :beer, :wine
|
39
|
+
end
|
40
|
+
end
|
41
|
+
post '/nested-hash' do
|
42
|
+
end
|
43
|
+
|
44
|
+
params do
|
45
|
+
requires :items, type: Array do
|
46
|
+
optional :beer, :wine, type: Boolean
|
47
|
+
all_or_none_of :beer, :wine
|
48
|
+
end
|
49
|
+
end
|
50
|
+
post '/nested-array' do
|
51
|
+
end
|
10
52
|
|
11
|
-
|
53
|
+
params do
|
54
|
+
requires :items, type: Array do
|
55
|
+
requires :nested_items, type: Array do
|
56
|
+
optional :beer, :wine, type: Boolean
|
57
|
+
all_or_none_of :beer, :wine
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
post '/deeply-nested-array' do
|
62
|
+
end
|
63
|
+
end
|
12
64
|
end
|
13
65
|
end
|
14
|
-
|
15
|
-
|
66
|
+
|
67
|
+
def app
|
68
|
+
ValidationsSpec::AllOrNoneOfValidatorSpec::API
|
69
|
+
end
|
16
70
|
|
17
71
|
context 'when all restricted params are present' do
|
18
|
-
let(:
|
72
|
+
let(:path) { '/' }
|
73
|
+
let(:params) { { beer: true, wine: true } }
|
19
74
|
|
20
|
-
it 'does not
|
21
|
-
|
75
|
+
it 'does not return a validation error' do
|
76
|
+
validate
|
77
|
+
expect(last_response.status).to eq 201
|
22
78
|
end
|
23
79
|
|
24
80
|
context 'mixed with other params' do
|
25
|
-
let(:
|
81
|
+
let(:path) { '/mixed-params' }
|
82
|
+
let(:params) { { beer: true, wine: true, other: true } }
|
26
83
|
|
27
|
-
it 'does not
|
28
|
-
|
84
|
+
it 'does not return a validation error' do
|
85
|
+
validate
|
86
|
+
expect(last_response.status).to eq 201
|
29
87
|
end
|
30
88
|
end
|
31
89
|
end
|
32
90
|
|
33
|
-
context 'when
|
91
|
+
context 'when a subset of restricted params are present' do
|
92
|
+
let(:path) { '/' }
|
93
|
+
let(:params) { { beer: true } }
|
94
|
+
|
95
|
+
it 'returns a validation error' do
|
96
|
+
validate
|
97
|
+
expect(last_response.status).to eq 400
|
98
|
+
expect(JSON.parse(last_response.body)).to eq(
|
99
|
+
'beer,wine' => ['provide all or none of parameters']
|
100
|
+
)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when custom message is specified' do
|
105
|
+
let(:path) { '/custom-message' }
|
106
|
+
let(:params) { { beer: true } }
|
107
|
+
|
108
|
+
it 'returns a validation error' do
|
109
|
+
validate
|
110
|
+
expect(last_response.status).to eq 400
|
111
|
+
expect(JSON.parse(last_response.body)).to eq(
|
112
|
+
'beer,wine' => ['choose all or none']
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when no restricted params are present' do
|
118
|
+
let(:path) { '/' }
|
34
119
|
let(:params) { { somethingelse: true } }
|
35
120
|
|
36
|
-
it 'does not
|
37
|
-
|
121
|
+
it 'does not return a validation error' do
|
122
|
+
validate
|
123
|
+
expect(last_response.status).to eq 201
|
38
124
|
end
|
39
125
|
end
|
40
126
|
|
41
|
-
context 'when
|
42
|
-
let(:
|
127
|
+
context 'when restricted params are nested inside required hash' do
|
128
|
+
let(:path) { '/nested-hash' }
|
129
|
+
let(:params) { { item: { beer: true } } }
|
43
130
|
|
44
|
-
it '
|
45
|
-
|
46
|
-
|
47
|
-
|
131
|
+
it 'returns a validation error with full names of the params' do
|
132
|
+
validate
|
133
|
+
expect(last_response.status).to eq 400
|
134
|
+
expect(JSON.parse(last_response.body)).to eq(
|
135
|
+
'item[beer],item[wine]' => ['provide all or none of parameters']
|
136
|
+
)
|
48
137
|
end
|
49
|
-
|
50
|
-
let(:mixed_params) { params.merge!(other: true, andanother: true) }
|
138
|
+
end
|
51
139
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
140
|
+
context 'when mutually exclusive params are nested inside array' do
|
141
|
+
let(:path) { '/nested-array' }
|
142
|
+
let(:params) { { items: [{ beer: true, wine: true }, { wine: true }] } }
|
143
|
+
|
144
|
+
it 'returns a validation error with full names of the params' do
|
145
|
+
validate
|
146
|
+
expect(last_response.status).to eq 400
|
147
|
+
expect(JSON.parse(last_response.body)).to eq(
|
148
|
+
'items[1][beer],items[1][wine]' => ['provide all or none of parameters']
|
149
|
+
)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'when mutually exclusive params are deeply nested' do
|
154
|
+
let(:path) { '/deeply-nested-array' }
|
155
|
+
let(:params) { { items: [{ nested_items: [{ beer: true }] }] } }
|
156
|
+
|
157
|
+
it 'returns a validation error with full names of the params' do
|
158
|
+
validate
|
159
|
+
expect(last_response.status).to eq 400
|
160
|
+
expect(JSON.parse(last_response.body)).to eq(
|
161
|
+
'items[0][nested_items][0][beer],items[0][nested_items][0][wine]' => [
|
162
|
+
'provide all or none of parameters'
|
163
|
+
]
|
164
|
+
)
|
57
165
|
end
|
58
166
|
end
|
59
167
|
end
|