grape 1.1.0 → 1.5.3
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 +278 -44
- data/LICENSE +1 -1
- data/README.md +514 -69
- data/UPGRADING.md +424 -17
- data/grape.gemspec +13 -2
- data/lib/grape.rb +104 -71
- data/lib/grape/api.rb +138 -175
- data/lib/grape/api/helpers.rb +2 -0
- data/lib/grape/api/instance.rb +283 -0
- data/lib/grape/config.rb +34 -0
- data/lib/grape/content_types.rb +34 -0
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dsl/api.rb +2 -0
- data/lib/grape/dsl/callbacks.rb +22 -0
- data/lib/grape/dsl/configuration.rb +2 -0
- data/lib/grape/dsl/desc.rb +41 -7
- data/lib/grape/dsl/headers.rb +2 -0
- data/lib/grape/dsl/helpers.rb +5 -2
- data/lib/grape/dsl/inside_route.rb +92 -49
- data/lib/grape/dsl/logger.rb +2 -0
- data/lib/grape/dsl/middleware.rb +9 -0
- data/lib/grape/dsl/parameters.rb +25 -14
- data/lib/grape/dsl/request_response.rb +4 -2
- data/lib/grape/dsl/routing.rb +17 -10
- data/lib/grape/dsl/settings.rb +7 -1
- data/lib/grape/dsl/validations.rb +24 -4
- data/lib/grape/eager_load.rb +20 -0
- data/lib/grape/endpoint.rb +59 -35
- data/lib/grape/error_formatter.rb +4 -2
- data/lib/grape/error_formatter/base.rb +2 -0
- data/lib/grape/error_formatter/json.rb +2 -0
- data/lib/grape/error_formatter/txt.rb +2 -0
- data/lib/grape/error_formatter/xml.rb +2 -0
- data/lib/grape/exceptions/base.rb +20 -14
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
- data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
- data/lib/grape/exceptions/invalid_formatter.rb +2 -0
- data/lib/grape/exceptions/invalid_message_body.rb +2 -0
- data/lib/grape/exceptions/invalid_response.rb +11 -0
- data/lib/grape/exceptions/invalid_version_header.rb +2 -0
- data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
- data/lib/grape/exceptions/method_not_allowed.rb +2 -0
- data/lib/grape/exceptions/missing_group_type.rb +2 -0
- data/lib/grape/exceptions/missing_mime_type.rb +2 -0
- data/lib/grape/exceptions/missing_option.rb +2 -0
- data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
- data/lib/grape/exceptions/unknown_options.rb +2 -0
- data/lib/grape/exceptions/unknown_parameter.rb +2 -0
- data/lib/grape/exceptions/unknown_validator.rb +2 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +2 -0
- data/lib/grape/exceptions/validation.rb +4 -2
- data/lib/grape/exceptions/validation_array_errors.rb +2 -0
- data/lib/grape/exceptions/validation_errors.rb +16 -13
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
- data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
- data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
- data/lib/grape/extensions/hash.rb +2 -0
- data/lib/grape/extensions/hashie/mash.rb +2 -0
- data/lib/grape/formatter.rb +5 -3
- data/lib/grape/formatter/json.rb +2 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -0
- data/lib/grape/formatter/txt.rb +2 -0
- data/lib/grape/formatter/xml.rb +2 -0
- data/lib/grape/http/headers.rb +50 -18
- data/lib/grape/locale/en.yml +3 -1
- data/lib/grape/middleware/auth/base.rb +7 -7
- data/lib/grape/middleware/auth/dsl.rb +2 -0
- data/lib/grape/middleware/auth/strategies.rb +2 -0
- data/lib/grape/middleware/auth/strategy_info.rb +2 -0
- data/lib/grape/middleware/base.rb +10 -7
- data/lib/grape/middleware/error.rb +21 -16
- data/lib/grape/middleware/filter.rb +2 -0
- data/lib/grape/middleware/formatter.rb +8 -6
- data/lib/grape/middleware/globals.rb +2 -0
- data/lib/grape/middleware/helpers.rb +12 -0
- data/lib/grape/middleware/stack.rb +13 -3
- data/lib/grape/middleware/versioner.rb +2 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +2 -0
- data/lib/grape/middleware/versioner/header.rb +10 -8
- data/lib/grape/middleware/versioner/param.rb +3 -1
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +4 -1
- data/lib/grape/middleware/versioner/path.rb +3 -1
- data/lib/grape/namespace.rb +14 -2
- data/lib/grape/parser.rb +4 -2
- data/lib/grape/parser/json.rb +3 -1
- data/lib/grape/parser/xml.rb +3 -1
- data/lib/grape/path.rb +15 -3
- data/lib/grape/presenters/presenter.rb +2 -0
- data/lib/grape/request.rb +19 -10
- data/lib/grape/router.rb +30 -29
- data/lib/grape/router/attribute_translator.rb +41 -8
- data/lib/grape/router/pattern.rb +20 -16
- data/lib/grape/router/route.rb +14 -28
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
- data/lib/grape/util/base_inheritable.rb +43 -0
- data/lib/grape/util/cache.rb +20 -0
- data/lib/grape/util/endpoint_configuration.rb +8 -0
- data/lib/grape/util/env.rb +19 -17
- data/lib/grape/util/inheritable_setting.rb +2 -0
- data/lib/grape/util/inheritable_values.rb +7 -25
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/lazy_block.rb +27 -0
- data/lib/grape/util/lazy_object.rb +43 -0
- data/lib/grape/util/lazy_value.rb +98 -0
- data/lib/grape/util/registrable.rb +2 -0
- data/lib/grape/util/reverse_stackable_values.rb +10 -35
- data/lib/grape/util/stackable_values.rb +21 -34
- data/lib/grape/util/strict_hash_configuration.rb +2 -0
- data/lib/grape/util/xml.rb +2 -0
- data/lib/grape/validations.rb +2 -0
- data/lib/grape/validations/attributes_iterator.rb +16 -6
- data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
- data/lib/grape/validations/params_scope.rb +51 -30
- data/lib/grape/validations/single_attribute_iterator.rb +24 -0
- data/lib/grape/validations/types.rb +13 -38
- data/lib/grape/validations/types/array_coercer.rb +65 -0
- data/lib/grape/validations/types/build_coercer.rb +47 -49
- data/lib/grape/validations/types/custom_type_coercer.rb +29 -51
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
- data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
- data/lib/grape/validations/types/file.rb +22 -18
- data/lib/grape/validations/types/invalid_value.rb +24 -0
- data/lib/grape/validations/types/json.rb +46 -39
- data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
- data/lib/grape/validations/types/primitive_coercer.rb +67 -0
- data/lib/grape/validations/types/set_coercer.rb +40 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
- data/lib/grape/validations/validator_factory.rb +8 -11
- data/lib/grape/validations/validators/all_or_none.rb +8 -13
- data/lib/grape/validations/validators/allow_blank.rb +3 -1
- data/lib/grape/validations/validators/as.rb +5 -4
- data/lib/grape/validations/validators/at_least_one_of.rb +7 -13
- data/lib/grape/validations/validators/base.rb +20 -16
- data/lib/grape/validations/validators/coerce.rb +46 -29
- data/lib/grape/validations/validators/default.rb +6 -6
- data/lib/grape/validations/validators/exactly_one_of.rb +10 -23
- data/lib/grape/validations/validators/except_values.rb +4 -2
- data/lib/grape/validations/validators/multiple_params_base.rb +17 -10
- data/lib/grape/validations/validators/mutual_exclusion.rb +8 -18
- data/lib/grape/validations/validators/presence.rb +3 -1
- data/lib/grape/validations/validators/regexp.rb +4 -2
- data/lib/grape/validations/validators/same_as.rb +26 -0
- data/lib/grape/validations/validators/values.rb +18 -6
- data/lib/grape/version.rb +3 -1
- data/spec/grape/api/custom_validations_spec.rb +5 -3
- data/spec/grape/api/deeply_included_options_spec.rb +2 -0
- data/spec/grape/api/defines_boolean_in_params_spec.rb +39 -0
- data/spec/grape/api/inherited_helpers_spec.rb +2 -0
- data/spec/grape/api/instance_spec.rb +104 -0
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/nested_helpers_spec.rb +2 -0
- data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/parameters_modification_spec.rb +3 -1
- data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +2 -0
- data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
- data/spec/grape/api/routes_with_requirements_spec.rb +61 -0
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +2 -0
- data/spec/grape/api/shared_helpers_spec.rb +2 -0
- data/spec/grape/api_remount_spec.rb +473 -0
- data/spec/grape/api_spec.rb +565 -12
- data/spec/grape/config_spec.rb +19 -0
- data/spec/grape/dsl/callbacks_spec.rb +2 -0
- data/spec/grape/dsl/configuration_spec.rb +2 -0
- data/spec/grape/dsl/desc_spec.rb +42 -16
- data/spec/grape/dsl/headers_spec.rb +2 -0
- data/spec/grape/dsl/helpers_spec.rb +4 -2
- data/spec/grape/dsl/inside_route_spec.rb +184 -33
- data/spec/grape/dsl/logger_spec.rb +2 -0
- data/spec/grape/dsl/middleware_spec.rb +10 -0
- data/spec/grape/dsl/parameters_spec.rb +2 -0
- data/spec/grape/dsl/request_response_spec.rb +2 -0
- data/spec/grape/dsl/routing_spec.rb +12 -0
- data/spec/grape/dsl/settings_spec.rb +2 -0
- data/spec/grape/dsl/validations_spec.rb +2 -0
- data/spec/grape/endpoint/declared_spec.rb +601 -0
- data/spec/grape/endpoint_spec.rb +53 -523
- data/spec/grape/entity_spec.rb +9 -1
- data/spec/grape/exceptions/base_spec.rb +67 -0
- data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_response_spec.rb +13 -0
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -0
- data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
- data/spec/grape/exceptions/missing_option_spec.rb +2 -0
- data/spec/grape/exceptions/unknown_options_spec.rb +2 -0
- data/spec/grape/exceptions/unknown_validator_spec.rb +2 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +8 -4
- data/spec/grape/exceptions/validation_spec.rb +3 -1
- data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
- data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
- data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
- data/spec/grape/integration/rack_spec.rb +25 -7
- data/spec/grape/loading_spec.rb +2 -0
- data/spec/grape/middleware/auth/base_spec.rb +2 -0
- data/spec/grape/middleware/auth/dsl_spec.rb +5 -3
- data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
- data/spec/grape/middleware/base_spec.rb +10 -0
- data/spec/grape/middleware/error_spec.rb +3 -1
- data/spec/grape/middleware/exception_spec.rb +4 -2
- data/spec/grape/middleware/formatter_spec.rb +33 -16
- data/spec/grape/middleware/globals_spec.rb +2 -0
- data/spec/grape/middleware/stack_spec.rb +12 -0
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
- data/spec/grape/middleware/versioner/header_spec.rb +9 -1
- data/spec/grape/middleware/versioner/param_spec.rb +3 -1
- data/spec/grape/middleware/versioner/path_spec.rb +3 -1
- data/spec/grape/middleware/versioner_spec.rb +2 -0
- data/spec/grape/named_api_spec.rb +21 -0
- data/spec/grape/parser_spec.rb +7 -5
- data/spec/grape/path_spec.rb +6 -4
- data/spec/grape/presenters/presenter_spec.rb +2 -0
- data/spec/grape/request_spec.rb +26 -0
- data/spec/grape/util/inheritable_setting_spec.rb +2 -0
- data/spec/grape/util/inheritable_values_spec.rb +2 -0
- data/spec/grape/util/reverse_stackable_values_spec.rb +2 -0
- data/spec/grape/util/stackable_values_spec.rb +3 -1
- data/spec/grape/util/strict_hash_configuration_spec.rb +2 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
- data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +41 -0
- data/spec/grape/validations/params_scope_spec.rb +213 -9
- data/spec/grape/validations/single_attribute_iterator_spec.rb +58 -0
- data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
- data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
- data/spec/grape/validations/types_spec.rb +9 -36
- data/spec/grape/validations/validators/all_or_none_spec.rb +140 -30
- data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +175 -29
- data/spec/grape/validations/validators/coerce_spec.rb +476 -135
- data/spec/grape/validations/validators/default_spec.rb +172 -0
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +204 -38
- data/spec/grape/validations/validators/except_values_spec.rb +4 -1
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +186 -27
- data/spec/grape/validations/validators/presence_spec.rb +30 -0
- data/spec/grape/validations/validators/regexp_spec.rb +2 -0
- data/spec/grape/validations/validators/same_as_spec.rb +65 -0
- data/spec/grape/validations/validators/values_spec.rb +30 -5
- data/spec/grape/validations_spec.rb +388 -50
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/integration/multi_json/json_spec.rb +2 -0
- data/spec/integration/multi_xml/xml_spec.rb +2 -0
- data/spec/shared/versioning_examples.rb +22 -20
- data/spec/spec_helper.rb +12 -1
- data/spec/support/basic_auth_encode_helpers.rb +2 -0
- data/spec/support/chunks.rb +14 -0
- data/spec/support/content_type_helpers.rb +2 -0
- data/spec/support/eager_load.rb +19 -0
- data/spec/support/endpoint_faker.rb +2 -0
- data/spec/support/file_streamer.rb +2 -0
- data/spec/support/integer_helpers.rb +2 -0
- data/spec/support/versioned_helpers.rb +8 -8
- metadata +86 -48
- 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/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
- data/lib/grape/util/content_types.rb +0 -26
- data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
- data/pkg/grape-0.17.0.gem +0 -0
- data/pkg/grape-0.19.0.gem +0 -0
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Grape::Validations do
|
@@ -7,16 +9,23 @@ describe Grape::Validations do
|
|
7
9
|
subject
|
8
10
|
end
|
9
11
|
|
12
|
+
def declared_params
|
13
|
+
subject.namespace_stackable(:declared_params).flatten
|
14
|
+
end
|
15
|
+
|
10
16
|
describe 'params' do
|
11
17
|
context 'optional' do
|
12
|
-
|
18
|
+
before do
|
13
19
|
subject.params do
|
14
20
|
optional :a_number, regexp: /^[0-9]+$/
|
21
|
+
optional :attachment, type: File
|
15
22
|
end
|
16
23
|
subject.get '/optional' do
|
17
24
|
'optional works!'
|
18
25
|
end
|
26
|
+
end
|
19
27
|
|
28
|
+
it 'validates when params is present' do
|
20
29
|
get '/optional', a_number: 'string'
|
21
30
|
expect(last_response.status).to eq(400)
|
22
31
|
expect(last_response.body).to eq('a_number is invalid')
|
@@ -27,14 +36,7 @@ describe Grape::Validations do
|
|
27
36
|
end
|
28
37
|
|
29
38
|
it "doesn't validate when param not present" do
|
30
|
-
|
31
|
-
optional :a_number, regexp: /^[0-9]+$/
|
32
|
-
end
|
33
|
-
subject.get '/optional' do
|
34
|
-
'optional works!'
|
35
|
-
end
|
36
|
-
|
37
|
-
get '/optional'
|
39
|
+
get '/optional', a_number: nil, attachment: nil
|
38
40
|
expect(last_response.status).to eq(200)
|
39
41
|
expect(last_response.body).to eq('optional works!')
|
40
42
|
end
|
@@ -43,7 +45,7 @@ describe Grape::Validations do
|
|
43
45
|
subject.params do
|
44
46
|
optional :some_param
|
45
47
|
end
|
46
|
-
expect(
|
48
|
+
expect(declared_params).to eq([:some_param])
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
@@ -63,7 +65,7 @@ describe Grape::Validations do
|
|
63
65
|
|
64
66
|
it 'adds entity documentation to declared params' do
|
65
67
|
define_optional_using
|
66
|
-
expect(
|
68
|
+
expect(declared_params).to eq(%i[field_a field_b])
|
67
69
|
end
|
68
70
|
|
69
71
|
it 'works when field_a and field_b are not present' do
|
@@ -110,7 +112,7 @@ describe Grape::Validations do
|
|
110
112
|
subject.params do
|
111
113
|
requires :some_param
|
112
114
|
end
|
113
|
-
expect(
|
115
|
+
expect(declared_params).to eq([:some_param])
|
114
116
|
end
|
115
117
|
|
116
118
|
it 'works when required field is present but nil' do
|
@@ -120,6 +122,62 @@ describe Grape::Validations do
|
|
120
122
|
end
|
121
123
|
end
|
122
124
|
|
125
|
+
context 'requires with nested params' do
|
126
|
+
before do
|
127
|
+
subject.params do
|
128
|
+
requires :first_level, type: Hash do
|
129
|
+
optional :second_level, type: Array do
|
130
|
+
requires :value, type: Integer
|
131
|
+
optional :name, type: String
|
132
|
+
optional :third_level, type: Array do
|
133
|
+
requires :value, type: Integer
|
134
|
+
optional :name, type: String
|
135
|
+
optional :fourth_level, type: Array do
|
136
|
+
requires :value, type: Integer
|
137
|
+
optional :name, type: String
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
subject.put('/required') { 'required works' }
|
144
|
+
end
|
145
|
+
|
146
|
+
let(:request_params) do
|
147
|
+
{
|
148
|
+
first_level: {
|
149
|
+
second_level: [
|
150
|
+
{ value: 1, name: 'Lisa' },
|
151
|
+
{
|
152
|
+
value: 2,
|
153
|
+
name: 'James',
|
154
|
+
third_level: [
|
155
|
+
{ value: 'three', name: 'Sophie' },
|
156
|
+
{
|
157
|
+
value: 4,
|
158
|
+
name: 'Jenny',
|
159
|
+
fourth_level: [
|
160
|
+
{ name: 'Samuel' }, { value: 6, name: 'Jane' }
|
161
|
+
]
|
162
|
+
}
|
163
|
+
]
|
164
|
+
}
|
165
|
+
]
|
166
|
+
}
|
167
|
+
}
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'validates correctly in deep nested params' do
|
171
|
+
put '/required', request_params.to_json, 'CONTENT_TYPE' => 'application/json'
|
172
|
+
|
173
|
+
expect(last_response.status).to eq(400)
|
174
|
+
expect(last_response.body).to eq(
|
175
|
+
'first_level[second_level][1][third_level][0][value] is invalid, ' \
|
176
|
+
'first_level[second_level][1][third_level][1][fourth_level][0][value] is missing'
|
177
|
+
)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
123
181
|
context 'requires :all using Grape::Entity documentation' do
|
124
182
|
def define_requires_all
|
125
183
|
documentation = {
|
@@ -139,7 +197,7 @@ describe Grape::Validations do
|
|
139
197
|
|
140
198
|
it 'adds entity documentation to declared params' do
|
141
199
|
define_requires_all
|
142
|
-
expect(
|
200
|
+
expect(declared_params).to eq(%i[required_field optional_field])
|
143
201
|
end
|
144
202
|
|
145
203
|
it 'errors when required_field is not present' do
|
@@ -174,7 +232,7 @@ describe Grape::Validations do
|
|
174
232
|
|
175
233
|
it 'adds entity documentation to declared params' do
|
176
234
|
define_requires_none
|
177
|
-
expect(
|
235
|
+
expect(declared_params).to eq(%i[required_field optional_field])
|
178
236
|
end
|
179
237
|
|
180
238
|
it 'errors when required_field is not present' do
|
@@ -204,7 +262,7 @@ describe Grape::Validations do
|
|
204
262
|
|
205
263
|
it 'adds only the entity documentation to declared params, nothing more' do
|
206
264
|
define_requires_all
|
207
|
-
expect(
|
265
|
+
expect(declared_params).to eq(%i[required_field optional_field])
|
208
266
|
end
|
209
267
|
end
|
210
268
|
|
@@ -270,7 +328,7 @@ describe Grape::Validations do
|
|
270
328
|
requires :key
|
271
329
|
end
|
272
330
|
end
|
273
|
-
expect(
|
331
|
+
expect(declared_params).to eq([items: [:key]])
|
274
332
|
end
|
275
333
|
end
|
276
334
|
|
@@ -342,7 +400,7 @@ describe Grape::Validations do
|
|
342
400
|
requires :key
|
343
401
|
end
|
344
402
|
end
|
345
|
-
expect(
|
403
|
+
expect(declared_params).to eq([items: [:key]])
|
346
404
|
end
|
347
405
|
end
|
348
406
|
|
@@ -405,7 +463,7 @@ describe Grape::Validations do
|
|
405
463
|
requires :key
|
406
464
|
end
|
407
465
|
end
|
408
|
-
expect(
|
466
|
+
expect(declared_params).to eq([items: [:key]])
|
409
467
|
end
|
410
468
|
end
|
411
469
|
|
@@ -436,7 +494,7 @@ describe Grape::Validations do
|
|
436
494
|
class DateRangeValidator < Grape::Validations::Base
|
437
495
|
def validate_param!(attr_name, params)
|
438
496
|
return if params[attr_name][:from] <= params[attr_name][:to]
|
439
|
-
raise Grape::Exceptions::Validation
|
497
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "'from' must be lower or equal to 'to'")
|
440
498
|
end
|
441
499
|
end
|
442
500
|
end
|
@@ -520,7 +578,7 @@ describe Grape::Validations do
|
|
520
578
|
# NOTE: with body parameters in json or XML or similar this
|
521
579
|
# should actually fail with: children[parents][name] is missing.
|
522
580
|
expect(last_response.status).to eq(400)
|
523
|
-
expect(last_response.body).to eq('children[1][parents] is missing')
|
581
|
+
expect(last_response.body).to eq('children[1][parents] is missing, children[0][parents][1][name] is missing, children[0][parents][1][name] is empty')
|
524
582
|
end
|
525
583
|
|
526
584
|
it 'errors when a parameter is not present in array within array' do
|
@@ -540,7 +598,10 @@ describe Grape::Validations do
|
|
540
598
|
]
|
541
599
|
|
542
600
|
expect(last_response.status).to eq(400)
|
543
|
-
expect(last_response.body).to eq(
|
601
|
+
expect(last_response.body).to eq(
|
602
|
+
'children[0][parents][0][name] is missing, ' \
|
603
|
+
'children[1][parents][0][name] is missing'
|
604
|
+
)
|
544
605
|
end
|
545
606
|
|
546
607
|
it 'safely handles empty arrays and blank parameters' do
|
@@ -548,10 +609,17 @@ describe Grape::Validations do
|
|
548
609
|
# should actually return 200, since an empty array is valid.
|
549
610
|
get '/within_array', children: []
|
550
611
|
expect(last_response.status).to eq(400)
|
551
|
-
expect(last_response.body).to eq(
|
612
|
+
expect(last_response.body).to eq(
|
613
|
+
'children[0][name] is missing, ' \
|
614
|
+
'children[0][parents] is missing, ' \
|
615
|
+
'children[0][parents] is invalid, ' \
|
616
|
+
'children[0][parents][0][name] is missing, ' \
|
617
|
+
'children[0][parents][0][name] is empty'
|
618
|
+
)
|
619
|
+
|
552
620
|
get '/within_array', children: [name: 'Jay']
|
553
621
|
expect(last_response.status).to eq(400)
|
554
|
-
expect(last_response.body).to eq('children[0][parents] is missing')
|
622
|
+
expect(last_response.body).to eq('children[0][parents] is missing, children[0][parents][0][name] is missing, children[0][parents][0][name] is empty')
|
555
623
|
end
|
556
624
|
|
557
625
|
it 'errors when param is not an Array' do
|
@@ -699,7 +767,7 @@ describe Grape::Validations do
|
|
699
767
|
expect(last_response.status).to eq(200)
|
700
768
|
put_with_json '/within_array', children: [name: 'Jay']
|
701
769
|
expect(last_response.status).to eq(400)
|
702
|
-
expect(last_response.body).to eq('children[0][parents] is missing')
|
770
|
+
expect(last_response.body).to eq('children[0][parents] is missing, children[0][parents][0][name] is missing')
|
703
771
|
end
|
704
772
|
end
|
705
773
|
|
@@ -749,7 +817,7 @@ describe Grape::Validations do
|
|
749
817
|
requires :key
|
750
818
|
end
|
751
819
|
end
|
752
|
-
expect(
|
820
|
+
expect(declared_params).to eq([items: [:key]])
|
753
821
|
end
|
754
822
|
end
|
755
823
|
|
@@ -774,7 +842,7 @@ describe Grape::Validations do
|
|
774
842
|
it 'does internal validations if the outer group is present' do
|
775
843
|
get '/nested_optional_group', items: [{ key: 'foo' }]
|
776
844
|
expect(last_response.status).to eq(400)
|
777
|
-
expect(last_response.body).to eq('items[0][required_subitems] is missing')
|
845
|
+
expect(last_response.body).to eq('items[0][required_subitems] is missing, items[0][required_subitems][0][value] is missing')
|
778
846
|
|
779
847
|
get '/nested_optional_group', items: [{ key: 'foo', required_subitems: [{ value: 'bar' }] }]
|
780
848
|
expect(last_response.status).to eq(200)
|
@@ -794,7 +862,7 @@ describe Grape::Validations do
|
|
794
862
|
it 'handles validation within arrays' do
|
795
863
|
get '/nested_optional_group', items: [{ key: 'foo' }]
|
796
864
|
expect(last_response.status).to eq(400)
|
797
|
-
expect(last_response.body).to eq('items[0][required_subitems] is missing')
|
865
|
+
expect(last_response.body).to eq('items[0][required_subitems] is missing, items[0][required_subitems][0][value] is missing')
|
798
866
|
|
799
867
|
get '/nested_optional_group', items: [{ key: 'foo', required_subitems: [{ value: 'bar' }] }]
|
800
868
|
expect(last_response.status).to eq(200)
|
@@ -813,7 +881,275 @@ describe Grape::Validations do
|
|
813
881
|
requires(:required_subitems, type: Array) { requires :value }
|
814
882
|
end
|
815
883
|
end
|
816
|
-
expect(
|
884
|
+
expect(declared_params).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]])
|
885
|
+
end
|
886
|
+
|
887
|
+
context <<~DESC do
|
888
|
+
Issue occurs whenever:
|
889
|
+
* param structure with at least three levels
|
890
|
+
* 1st level item is a required Array that has >1 entry with an optional item present and >1 entry with an optional item missing
|
891
|
+
* 2nd level is an optional Array or Hash
|
892
|
+
* 3rd level is a required item (can be any type)
|
893
|
+
* additional levels do not effect the issue from occuring
|
894
|
+
DESC
|
895
|
+
|
896
|
+
it "example based off actual real world use case" do
|
897
|
+
subject.params do
|
898
|
+
requires :orders, type: Array do
|
899
|
+
requires :id, type: Integer
|
900
|
+
optional :drugs, type: Array do
|
901
|
+
requires :batches, type: Array do
|
902
|
+
requires :batch_no, type: String
|
903
|
+
end
|
904
|
+
end
|
905
|
+
end
|
906
|
+
end
|
907
|
+
|
908
|
+
subject.get '/validate_required_arrays_under_optional_arrays' do
|
909
|
+
'validate_required_arrays_under_optional_arrays works!'
|
910
|
+
end
|
911
|
+
|
912
|
+
data = {
|
913
|
+
orders: [
|
914
|
+
{ id: 77, drugs: [{batches: [{batch_no: "A1234567"}]}]},
|
915
|
+
{ id: 70 }
|
916
|
+
]
|
917
|
+
}
|
918
|
+
|
919
|
+
get '/validate_required_arrays_under_optional_arrays', data
|
920
|
+
expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
|
921
|
+
expect(last_response.status).to eq(200)
|
922
|
+
end
|
923
|
+
|
924
|
+
it "simplest example using Array -> Array -> Hash -> String" do
|
925
|
+
subject.params do
|
926
|
+
requires :orders, type: Array do
|
927
|
+
requires :id, type: Integer
|
928
|
+
optional :drugs, type: Array do
|
929
|
+
requires :batch_no, type: String
|
930
|
+
end
|
931
|
+
end
|
932
|
+
end
|
933
|
+
|
934
|
+
subject.get '/validate_required_arrays_under_optional_arrays' do
|
935
|
+
'validate_required_arrays_under_optional_arrays works!'
|
936
|
+
end
|
937
|
+
|
938
|
+
data = {
|
939
|
+
orders: [
|
940
|
+
{ id: 77, drugs: [{batch_no: "A1234567"}]},
|
941
|
+
{ id: 70 }
|
942
|
+
]
|
943
|
+
}
|
944
|
+
|
945
|
+
get '/validate_required_arrays_under_optional_arrays', data
|
946
|
+
expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
|
947
|
+
expect(last_response.status).to eq(200)
|
948
|
+
end
|
949
|
+
|
950
|
+
it "simplest example using Array -> Hash -> String" do
|
951
|
+
subject.params do
|
952
|
+
requires :orders, type: Array do
|
953
|
+
requires :id, type: Integer
|
954
|
+
optional :drugs, type: Hash do
|
955
|
+
requires :batch_no, type: String
|
956
|
+
end
|
957
|
+
end
|
958
|
+
end
|
959
|
+
|
960
|
+
subject.get '/validate_required_arrays_under_optional_arrays' do
|
961
|
+
'validate_required_arrays_under_optional_arrays works!'
|
962
|
+
end
|
963
|
+
|
964
|
+
data = {
|
965
|
+
orders: [
|
966
|
+
{ id: 77, drugs: {batch_no: "A1234567"}},
|
967
|
+
{ id: 70 }
|
968
|
+
]
|
969
|
+
}
|
970
|
+
|
971
|
+
get '/validate_required_arrays_under_optional_arrays', data
|
972
|
+
expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
|
973
|
+
expect(last_response.status).to eq(200)
|
974
|
+
end
|
975
|
+
|
976
|
+
it "correctly indexes invalida data" do
|
977
|
+
subject.params do
|
978
|
+
requires :orders, type: Array do
|
979
|
+
requires :id, type: Integer
|
980
|
+
optional :drugs, type: Array do
|
981
|
+
requires :batch_no, type: String
|
982
|
+
requires :quantity, type: Integer
|
983
|
+
end
|
984
|
+
end
|
985
|
+
end
|
986
|
+
|
987
|
+
subject.get '/correctly_indexes' do
|
988
|
+
'correctly_indexes works!'
|
989
|
+
end
|
990
|
+
|
991
|
+
data = {
|
992
|
+
orders: [
|
993
|
+
{ id: 70 },
|
994
|
+
{ id: 77, drugs: [{batch_no: "A1234567", quantity: 12}, {batch_no: "B222222"}]}
|
995
|
+
]
|
996
|
+
}
|
997
|
+
|
998
|
+
get '/correctly_indexes', data
|
999
|
+
expect(last_response.body).to eq("orders[1][drugs][1][quantity] is missing")
|
1000
|
+
expect(last_response.status).to eq(400)
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
context "multiple levels of optional and requires settings" do
|
1004
|
+
before do
|
1005
|
+
subject.params do
|
1006
|
+
requires :top, type: Array do
|
1007
|
+
requires :top_id, type: Integer, allow_blank: false
|
1008
|
+
optional :middle_1, type: Array do
|
1009
|
+
requires :middle_1_id, type: Integer, allow_blank: false
|
1010
|
+
optional :middle_2, type: Array do
|
1011
|
+
requires :middle_2_id, type: String, allow_blank: false
|
1012
|
+
optional :bottom, type: Array do
|
1013
|
+
requires :bottom_id, type: Integer, allow_blank: false
|
1014
|
+
end
|
1015
|
+
end
|
1016
|
+
end
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
subject.get '/multi_level' do
|
1021
|
+
'multi_level works!'
|
1022
|
+
end
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
it "with valid data" do
|
1026
|
+
data = {
|
1027
|
+
top: [
|
1028
|
+
{ top_id: 1, middle_1: [
|
1029
|
+
{middle_1_id: 11}, {middle_1_id: 12, middle_2: [
|
1030
|
+
{middle_2_id: 121}, {middle_2_id: 122, bottom: [{bottom_id: 1221}]}]}]},
|
1031
|
+
{ top_id: 2, middle_1: [
|
1032
|
+
{middle_1_id: 21}, {middle_1_id: 22, middle_2: [
|
1033
|
+
{middle_2_id: 221}]}]},
|
1034
|
+
{ top_id: 3, middle_1: [
|
1035
|
+
{middle_1_id: 31}, {middle_1_id: 32}]},
|
1036
|
+
{ top_id: 4 }
|
1037
|
+
]
|
1038
|
+
}
|
1039
|
+
|
1040
|
+
get '/multi_level', data
|
1041
|
+
expect(last_response.body).to eq("multi_level works!")
|
1042
|
+
expect(last_response.status).to eq(200)
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
it "with invalid data" do
|
1046
|
+
data = {
|
1047
|
+
top: [
|
1048
|
+
{ top_id: 1, middle_1: [
|
1049
|
+
{middle_1_id: 11}, {middle_1_id: 12, middle_2: [
|
1050
|
+
{middle_2_id: 121}, {middle_2_id: 122, bottom: [{bottom_id: nil}]}]}]},
|
1051
|
+
{ top_id: 2, middle_1: [
|
1052
|
+
{middle_1_id: 21}, {middle_1_id: 22, middle_2: [{middle_2_id: nil}]}]},
|
1053
|
+
{ top_id: 3, middle_1: [
|
1054
|
+
{middle_1_id: nil}, {middle_1_id: 32}]},
|
1055
|
+
{ top_id: nil, missing_top_id: 4 }
|
1056
|
+
]
|
1057
|
+
}
|
1058
|
+
# debugger
|
1059
|
+
get '/multi_level', data
|
1060
|
+
expect(last_response.body.split(", ")).to match_array([
|
1061
|
+
"top[3][top_id] is empty",
|
1062
|
+
"top[2][middle_1][0][middle_1_id] is empty",
|
1063
|
+
"top[1][middle_1][1][middle_2][0][middle_2_id] is empty",
|
1064
|
+
"top[0][middle_1][1][middle_2][1][bottom][0][bottom_id] is empty"
|
1065
|
+
])
|
1066
|
+
expect(last_response.status).to eq(400)
|
1067
|
+
end
|
1068
|
+
end
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
it "exactly_one_of" do
|
1072
|
+
subject.params do
|
1073
|
+
requires :orders, type: Array do
|
1074
|
+
requires :id, type: Integer
|
1075
|
+
optional :drugs, type: Hash do
|
1076
|
+
optional :batch_no, type: String
|
1077
|
+
optional :batch_id, type: String
|
1078
|
+
exactly_one_of :batch_no, :batch_id
|
1079
|
+
end
|
1080
|
+
end
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
subject.get '/exactly_one_of' do
|
1084
|
+
'exactly_one_of works!'
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
data = {
|
1088
|
+
orders: [
|
1089
|
+
{ id: 77, drugs: {batch_no: "A1234567"}},
|
1090
|
+
{ id: 70 }
|
1091
|
+
]
|
1092
|
+
}
|
1093
|
+
|
1094
|
+
get '/exactly_one_of', data
|
1095
|
+
expect(last_response.body).to eq("exactly_one_of works!")
|
1096
|
+
expect(last_response.status).to eq(200)
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
it "at_least_one_of" do
|
1100
|
+
subject.params do
|
1101
|
+
requires :orders, type: Array do
|
1102
|
+
requires :id, type: Integer
|
1103
|
+
optional :drugs, type: Hash do
|
1104
|
+
optional :batch_no, type: String
|
1105
|
+
optional :batch_id, type: String
|
1106
|
+
at_least_one_of :batch_no, :batch_id
|
1107
|
+
end
|
1108
|
+
end
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
subject.get '/at_least_one_of' do
|
1112
|
+
'at_least_one_of works!'
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
data = {
|
1116
|
+
orders: [
|
1117
|
+
{ id: 77, drugs: {batch_no: "A1234567"}},
|
1118
|
+
{ id: 70 }
|
1119
|
+
]
|
1120
|
+
}
|
1121
|
+
|
1122
|
+
get '/at_least_one_of', data
|
1123
|
+
expect(last_response.body).to eq("at_least_one_of works!")
|
1124
|
+
expect(last_response.status).to eq(200)
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
it "all_or_none_of" do
|
1128
|
+
subject.params do
|
1129
|
+
requires :orders, type: Array do
|
1130
|
+
requires :id, type: Integer
|
1131
|
+
optional :drugs, type: Hash do
|
1132
|
+
optional :batch_no, type: String
|
1133
|
+
optional :batch_id, type: String
|
1134
|
+
all_or_none_of :batch_no, :batch_id
|
1135
|
+
end
|
1136
|
+
end
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
subject.get '/all_or_none_of' do
|
1140
|
+
'all_or_none_of works!'
|
1141
|
+
end
|
1142
|
+
|
1143
|
+
data = {
|
1144
|
+
orders: [
|
1145
|
+
{ id: 77, drugs: {batch_no: "A1234567", batch_id: "12"}},
|
1146
|
+
{ id: 70 }
|
1147
|
+
]
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
get '/all_or_none_of', data
|
1151
|
+
expect(last_response.body).to eq("all_or_none_of works!")
|
1152
|
+
expect(last_response.status).to eq(200)
|
817
1153
|
end
|
818
1154
|
end
|
819
1155
|
|
@@ -841,7 +1177,7 @@ describe Grape::Validations do
|
|
841
1177
|
class Customvalidator < Grape::Validations::Base
|
842
1178
|
def validate_param!(attr_name, params)
|
843
1179
|
return if params[attr_name] == 'im custom'
|
844
|
-
raise Grape::Exceptions::Validation
|
1180
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: 'is not custom!')
|
845
1181
|
end
|
846
1182
|
end
|
847
1183
|
end
|
@@ -989,7 +1325,7 @@ describe Grape::Validations do
|
|
989
1325
|
class CustomvalidatorWithOptions < Grape::Validations::Base
|
990
1326
|
def validate_param!(attr_name, params)
|
991
1327
|
return if params[attr_name] == @option[:text]
|
992
|
-
raise Grape::Exceptions::Validation
|
1328
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message)
|
993
1329
|
end
|
994
1330
|
end
|
995
1331
|
end
|
@@ -1013,7 +1349,7 @@ describe Grape::Validations do
|
|
1013
1349
|
expect(last_response.body).to eq('custom is not custom with options!')
|
1014
1350
|
end
|
1015
1351
|
end
|
1016
|
-
end
|
1352
|
+
end
|
1017
1353
|
|
1018
1354
|
context 'named' do
|
1019
1355
|
context 'can be defined' do
|
@@ -1058,14 +1394,14 @@ describe Grape::Validations do
|
|
1058
1394
|
subject.params do
|
1059
1395
|
use :pagination
|
1060
1396
|
end
|
1061
|
-
expect(
|
1397
|
+
expect(declared_params).to eq %i[page per_page]
|
1062
1398
|
end
|
1063
1399
|
|
1064
1400
|
it 'by #use with multiple params' do
|
1065
1401
|
subject.params do
|
1066
1402
|
use :pagination, :period
|
1067
1403
|
end
|
1068
|
-
expect(
|
1404
|
+
expect(declared_params).to eq %i[page per_page start_date end_date]
|
1069
1405
|
end
|
1070
1406
|
end
|
1071
1407
|
|
@@ -1223,7 +1559,9 @@ describe Grape::Validations do
|
|
1223
1559
|
end
|
1224
1560
|
get '/custom_message/mutually_exclusive', beer: 'true', wine: 'true', nested: { scotch: 'true', aquavit: 'true' }, nested2: [{ scotch2: 'true' }, { scotch2: 'true', aquavit2: 'true' }]
|
1225
1561
|
expect(last_response.status).to eq(400)
|
1226
|
-
expect(last_response.body).to eq
|
1562
|
+
expect(last_response.body).to eq(
|
1563
|
+
'beer, wine are mutually exclusive pass only one, nested[scotch], nested[aquavit] are mutually exclusive pass only one, nested2[1][scotch2], nested2[1][aquavit2] are mutually exclusive pass only one'
|
1564
|
+
)
|
1227
1565
|
end
|
1228
1566
|
end
|
1229
1567
|
|
@@ -1249,7 +1587,7 @@ describe Grape::Validations do
|
|
1249
1587
|
|
1250
1588
|
get '/mutually_exclusive', beer: 'true', wine: 'true', nested: { scotch: 'true', aquavit: 'true' }, nested2: [{ scotch2: 'true' }, { scotch2: 'true', aquavit2: 'true' }]
|
1251
1589
|
expect(last_response.status).to eq(400)
|
1252
|
-
expect(last_response.body).to eq 'beer, wine are mutually exclusive, scotch, aquavit are mutually exclusive, scotch2, aquavit2 are mutually exclusive'
|
1590
|
+
expect(last_response.body).to eq 'beer, wine are mutually exclusive, nested[scotch], nested[aquavit] are mutually exclusive, nested2[1][scotch2], nested2[1][aquavit2] are mutually exclusive'
|
1253
1591
|
end
|
1254
1592
|
end
|
1255
1593
|
|
@@ -1318,7 +1656,7 @@ describe Grape::Validations do
|
|
1318
1656
|
optional :beer
|
1319
1657
|
optional :wine
|
1320
1658
|
optional :juice
|
1321
|
-
exactly_one_of :beer, :wine, :juice, message:
|
1659
|
+
exactly_one_of :beer, :wine, :juice, message: 'are missing, exactly one parameter is required'
|
1322
1660
|
end
|
1323
1661
|
get '/exactly_one_of' do
|
1324
1662
|
'exactly_one_of works!'
|
@@ -1352,7 +1690,7 @@ describe Grape::Validations do
|
|
1352
1690
|
it 'errors when two or more are present' do
|
1353
1691
|
get '/custom_message/exactly_one_of', beer: 'string', wine: 'anotherstring'
|
1354
1692
|
expect(last_response.status).to eq(400)
|
1355
|
-
expect(last_response.body).to eq 'beer, wine are
|
1693
|
+
expect(last_response.body).to eq 'beer, wine are missing, exactly one parameter is required'
|
1356
1694
|
end
|
1357
1695
|
end
|
1358
1696
|
|
@@ -1399,7 +1737,7 @@ describe Grape::Validations do
|
|
1399
1737
|
it 'errors when none are present' do
|
1400
1738
|
get '/exactly_one_of_nested'
|
1401
1739
|
expect(last_response.status).to eq(400)
|
1402
|
-
expect(last_response.body).to eq 'nested is missing, beer_nested, wine_nested, juice_nested are missing, exactly one parameter must be provided'
|
1740
|
+
expect(last_response.body).to eq 'nested is missing, nested[beer_nested], nested[wine_nested], nested[juice_nested] are missing, exactly one parameter must be provided'
|
1403
1741
|
end
|
1404
1742
|
|
1405
1743
|
it 'succeeds when one is present' do
|
@@ -1411,7 +1749,7 @@ describe Grape::Validations do
|
|
1411
1749
|
it 'errors when two or more are present' do
|
1412
1750
|
get '/exactly_one_of_nested', nested: { beer_nested: 'string' }, nested2: [{ beer_nested2: 'string', wine_nested2: 'anotherstring' }]
|
1413
1751
|
expect(last_response.status).to eq(400)
|
1414
|
-
expect(last_response.body).to eq 'beer_nested2, wine_nested2 are mutually exclusive'
|
1752
|
+
expect(last_response.body).to eq 'nested2[0][beer_nested2], nested2[0][wine_nested2] are mutually exclusive'
|
1415
1753
|
end
|
1416
1754
|
end
|
1417
1755
|
end
|
@@ -1485,16 +1823,16 @@ describe Grape::Validations do
|
|
1485
1823
|
before :each do
|
1486
1824
|
subject.params do
|
1487
1825
|
requires :nested, type: Hash do
|
1488
|
-
optional :
|
1489
|
-
optional :
|
1490
|
-
optional :
|
1491
|
-
at_least_one_of :
|
1826
|
+
optional :beer
|
1827
|
+
optional :wine
|
1828
|
+
optional :juice
|
1829
|
+
at_least_one_of :beer, :wine, :juice
|
1492
1830
|
end
|
1493
1831
|
optional :nested2, type: Array do
|
1494
|
-
optional :
|
1495
|
-
optional :
|
1496
|
-
optional :
|
1497
|
-
at_least_one_of :
|
1832
|
+
optional :beer
|
1833
|
+
optional :wine
|
1834
|
+
optional :juice
|
1835
|
+
at_least_one_of :beer, :wine, :juice
|
1498
1836
|
end
|
1499
1837
|
end
|
1500
1838
|
subject.get '/at_least_one_of_nested' do
|
@@ -1505,17 +1843,17 @@ describe Grape::Validations do
|
|
1505
1843
|
it 'errors when none are present' do
|
1506
1844
|
get '/at_least_one_of_nested'
|
1507
1845
|
expect(last_response.status).to eq(400)
|
1508
|
-
expect(last_response.body).to eq 'nested is missing,
|
1846
|
+
expect(last_response.body).to eq 'nested is missing, nested[beer], nested[wine], nested[juice] are missing, at least one parameter must be provided'
|
1509
1847
|
end
|
1510
1848
|
|
1511
1849
|
it 'does not error when one is present' do
|
1512
|
-
get '/at_least_one_of_nested', nested: {
|
1850
|
+
get '/at_least_one_of_nested', nested: { beer: 'string' }, nested2: [{ beer: 'string' }]
|
1513
1851
|
expect(last_response.status).to eq(200)
|
1514
1852
|
expect(last_response.body).to eq 'at_least_one_of works!'
|
1515
1853
|
end
|
1516
1854
|
|
1517
1855
|
it 'does not error when two are present' do
|
1518
|
-
get '/at_least_one_of_nested', nested: {
|
1856
|
+
get '/at_least_one_of_nested', nested: { beer: 'string', wine: 'string' }, nested2: [{ beer: 'string', wine: 'string' }]
|
1519
1857
|
expect(last_response.status).to eq(200)
|
1520
1858
|
expect(last_response.body).to eq 'at_least_one_of works!'
|
1521
1859
|
end
|