grape 1.7.1 → 2.0.0
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 +37 -1
- data/CONTRIBUTING.md +1 -1
- data/README.md +30 -25
- data/UPGRADING.md +35 -0
- data/grape.gemspec +3 -6
- data/lib/grape/api.rb +2 -2
- data/lib/grape/content_types.rb +2 -8
- data/lib/grape/dsl/desc.rb +1 -1
- data/lib/grape/dsl/inside_route.rb +11 -11
- data/lib/grape/dsl/request_response.rb +2 -1
- data/lib/grape/dsl/settings.rb +2 -6
- data/lib/grape/endpoint.rb +28 -18
- data/lib/grape/error_formatter/base.rb +1 -1
- data/lib/grape/exceptions/base.rb +2 -2
- data/lib/grape/exceptions/missing_group_type.rb +1 -6
- data/lib/grape/exceptions/unsupported_group_type.rb +1 -6
- data/lib/grape/exceptions/validation_errors.rb +1 -6
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +3 -3
- data/lib/grape/extensions/hash.rb +4 -7
- data/lib/grape/extensions/hashie/mash.rb +3 -3
- data/lib/grape/formatter/serializable_hash.rb +7 -7
- data/lib/grape/http/headers.rb +12 -2
- data/lib/grape/middleware/auth/base.rb +1 -1
- data/lib/grape/middleware/auth/strategies.rb +1 -2
- data/lib/grape/middleware/error.rb +5 -5
- data/lib/grape/middleware/formatter.rb +6 -6
- data/lib/grape/middleware/versioner/header.rb +11 -19
- data/lib/grape/railtie.rb +9 -0
- data/lib/grape/request.rb +8 -2
- data/lib/grape/router/route.rb +1 -3
- data/lib/grape/util/lazy_value.rb +3 -11
- data/lib/grape/util/strict_hash_configuration.rb +3 -4
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/params_scope.rb +8 -2
- data/lib/grape/validations/single_attribute_iterator.rb +3 -1
- data/lib/grape/validations/types/custom_type_coercer.rb +2 -16
- data/lib/grape/validations/validators/base.rb +9 -20
- data/lib/grape/validations/validators/default_validator.rb +2 -20
- data/lib/grape/validations/validators/multiple_params_base.rb +4 -8
- data/lib/grape/validations/validators/values_validator.rb +14 -5
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +26 -5
- metadata +13 -253
- data/lib/grape/config.rb +0 -34
- data/lib/grape/extensions/deep_mergeable_hash.rb +0 -21
- data/lib/grape/extensions/deep_symbolize_hash.rb +0 -32
- data/spec/grape/api/custom_validations_spec.rb +0 -256
- data/spec/grape/api/deeply_included_options_spec.rb +0 -56
- data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
- data/spec/grape/api/documentation_spec.rb +0 -59
- data/spec/grape/api/inherited_helpers_spec.rb +0 -114
- data/spec/grape/api/instance_spec.rb +0 -103
- data/spec/grape/api/invalid_format_spec.rb +0 -45
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
- data/spec/grape/api/nested_helpers_spec.rb +0 -50
- data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
- data/spec/grape/api/parameters_modification_spec.rb +0 -41
- data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
- data/spec/grape/api/recognize_path_spec.rb +0 -21
- data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
- data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
- data/spec/grape/api/shared_helpers_spec.rb +0 -36
- data/spec/grape/api_remount_spec.rb +0 -473
- data/spec/grape/api_spec.rb +0 -4347
- data/spec/grape/config_spec.rb +0 -17
- data/spec/grape/dsl/callbacks_spec.rb +0 -45
- data/spec/grape/dsl/desc_spec.rb +0 -101
- data/spec/grape/dsl/headers_spec.rb +0 -62
- data/spec/grape/dsl/helpers_spec.rb +0 -100
- data/spec/grape/dsl/inside_route_spec.rb +0 -535
- data/spec/grape/dsl/logger_spec.rb +0 -24
- data/spec/grape/dsl/middleware_spec.rb +0 -60
- data/spec/grape/dsl/parameters_spec.rb +0 -180
- data/spec/grape/dsl/request_response_spec.rb +0 -206
- data/spec/grape/dsl/routing_spec.rb +0 -275
- data/spec/grape/dsl/settings_spec.rb +0 -261
- data/spec/grape/dsl/validations_spec.rb +0 -55
- data/spec/grape/endpoint/declared_spec.rb +0 -846
- data/spec/grape/endpoint_spec.rb +0 -1085
- data/spec/grape/entity_spec.rb +0 -336
- data/spec/grape/exceptions/base_spec.rb +0 -81
- data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -145
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
- data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
- data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
- data/spec/grape/exceptions/missing_group_type_spec.rb +0 -21
- data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
- data/spec/grape/exceptions/missing_option_spec.rb +0 -15
- data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
- data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
- data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -23
- data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
- data/spec/grape/exceptions/validation_spec.rb +0 -19
- data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
- data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
- data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
- data/spec/grape/integration/rack_spec.rb +0 -51
- data/spec/grape/loading_spec.rb +0 -44
- data/spec/grape/middleware/auth/base_spec.rb +0 -31
- data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
- data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
- data/spec/grape/middleware/base_spec.rb +0 -221
- data/spec/grape/middleware/error_spec.rb +0 -85
- data/spec/grape/middleware/exception_spec.rb +0 -294
- data/spec/grape/middleware/formatter_spec.rb +0 -461
- data/spec/grape/middleware/globals_spec.rb +0 -30
- data/spec/grape/middleware/stack_spec.rb +0 -155
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
- data/spec/grape/middleware/versioner/header_spec.rb +0 -345
- data/spec/grape/middleware/versioner/param_spec.rb +0 -171
- data/spec/grape/middleware/versioner/path_spec.rb +0 -62
- data/spec/grape/middleware/versioner_spec.rb +0 -21
- data/spec/grape/named_api_spec.rb +0 -19
- data/spec/grape/parser_spec.rb +0 -86
- data/spec/grape/path_spec.rb +0 -252
- data/spec/grape/presenters/presenter_spec.rb +0 -71
- data/spec/grape/request_spec.rb +0 -136
- data/spec/grape/util/inheritable_setting_spec.rb +0 -242
- data/spec/grape/util/inheritable_values_spec.rb +0 -79
- data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
- data/spec/grape/util/stackable_values_spec.rb +0 -128
- data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
- data/spec/grape/validations/attributes_doc_spec.rb +0 -153
- data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -40
- data/spec/grape/validations/params_scope_spec.rb +0 -1420
- data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -57
- data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
- data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
- data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
- data/spec/grape/validations/types_spec.rb +0 -111
- data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
- data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
- data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
- data/spec/grape/validations/validators/default_spec.rb +0 -463
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
- data/spec/grape/validations/validators/except_values_spec.rb +0 -192
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
- data/spec/grape/validations/validators/presence_spec.rb +0 -315
- data/spec/grape/validations/validators/regexp_spec.rb +0 -161
- data/spec/grape/validations/validators/same_as_spec.rb +0 -57
- data/spec/grape/validations/validators/values_spec.rb +0 -696
- data/spec/grape/validations/validators/zh-CN.yml +0 -10
- data/spec/grape/validations_spec.rb +0 -2029
- data/spec/integration/eager_load/eager_load_spec.rb +0 -15
- data/spec/integration/multi_json/json_spec.rb +0 -7
- data/spec/integration/multi_xml/xml_spec.rb +0 -7
- data/spec/shared/versioning_examples.rb +0 -215
- data/spec/spec_helper.rb +0 -52
- data/spec/support/basic_auth_encode_helpers.rb +0 -11
- data/spec/support/chunks.rb +0 -14
- data/spec/support/content_type_helpers.rb +0 -15
- data/spec/support/endpoint_faker.rb +0 -25
- data/spec/support/file_streamer.rb +0 -13
- data/spec/support/integer_helpers.rb +0 -13
- data/spec/support/versioned_helpers.rb +0 -55
@@ -1,192 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Grape::Validations::Validators::ExceptValuesValidator do
|
4
|
-
module ValidationsSpec
|
5
|
-
class ExceptValuesModel
|
6
|
-
DEFAULT_EXCEPTS = %w[invalid-type1 invalid-type2 invalid-type3].freeze
|
7
|
-
class << self
|
8
|
-
attr_accessor :excepts
|
9
|
-
|
10
|
-
def excepts
|
11
|
-
@excepts ||= []
|
12
|
-
[DEFAULT_EXCEPTS + @excepts].flatten.uniq
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
TEST_CASES = {
|
18
|
-
req_except: {
|
19
|
-
requires: { except_values: ExceptValuesModel.excepts },
|
20
|
-
tests: [
|
21
|
-
{ value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
22
|
-
{ value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
23
|
-
{ value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
|
24
|
-
]
|
25
|
-
},
|
26
|
-
req_except_hash: {
|
27
|
-
requires: { except_values: { value: ExceptValuesModel.excepts } },
|
28
|
-
tests: [
|
29
|
-
{ value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
30
|
-
{ value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
31
|
-
{ value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
|
32
|
-
]
|
33
|
-
},
|
34
|
-
req_except_custom_message: {
|
35
|
-
requires: { except_values: { value: ExceptValuesModel.excepts, message: 'is not allowed' } },
|
36
|
-
tests: [
|
37
|
-
{ value: 'invalid-type1', rc: 400, body: { error: 'type is not allowed' }.to_json },
|
38
|
-
{ value: 'invalid-type3', rc: 400, body: { error: 'type is not allowed' }.to_json },
|
39
|
-
{ value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
|
40
|
-
]
|
41
|
-
},
|
42
|
-
req_except_no_value: {
|
43
|
-
requires: { except_values: { message: 'is not allowed' } },
|
44
|
-
tests: [
|
45
|
-
{ value: 'invalid-type1', rc: 200, body: { type: 'invalid-type1' }.to_json }
|
46
|
-
]
|
47
|
-
},
|
48
|
-
req_except_empty: {
|
49
|
-
requires: { except_values: [] },
|
50
|
-
tests: [
|
51
|
-
{ value: 'invalid-type1', rc: 200, body: { type: 'invalid-type1' }.to_json }
|
52
|
-
]
|
53
|
-
},
|
54
|
-
req_except_lambda: {
|
55
|
-
requires: { except_values: -> { ExceptValuesModel.excepts } },
|
56
|
-
add_excepts: ['invalid-type4'],
|
57
|
-
tests: [
|
58
|
-
{ value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
59
|
-
{ value: 'invalid-type4', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
60
|
-
{ value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
|
61
|
-
]
|
62
|
-
},
|
63
|
-
req_except_lambda_custom_message: {
|
64
|
-
requires: { except_values: { value: -> { ExceptValuesModel.excepts }, message: 'is not allowed' } },
|
65
|
-
add_excepts: ['invalid-type4'],
|
66
|
-
tests: [
|
67
|
-
{ value: 'invalid-type1', rc: 400, body: { error: 'type is not allowed' }.to_json },
|
68
|
-
{ value: 'invalid-type4', rc: 400, body: { error: 'type is not allowed' }.to_json },
|
69
|
-
{ value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json }
|
70
|
-
]
|
71
|
-
},
|
72
|
-
opt_except_default: {
|
73
|
-
optional: { except_values: ExceptValuesModel.excepts, default: 'valid-type2' },
|
74
|
-
tests: [
|
75
|
-
{ value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
76
|
-
{ value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
77
|
-
{ value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json },
|
78
|
-
{ rc: 200, body: { type: 'valid-type2' }.to_json }
|
79
|
-
]
|
80
|
-
},
|
81
|
-
opt_except_lambda_default: {
|
82
|
-
optional: { except_values: -> { ExceptValuesModel.excepts }, default: 'valid-type2' },
|
83
|
-
tests: [
|
84
|
-
{ value: 'invalid-type1', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
85
|
-
{ value: 'invalid-type3', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
86
|
-
{ value: 'valid-type', rc: 200, body: { type: 'valid-type' }.to_json },
|
87
|
-
{ rc: 200, body: { type: 'valid-type2' }.to_json }
|
88
|
-
]
|
89
|
-
},
|
90
|
-
req_except_type_coerce: {
|
91
|
-
requires: { type: Integer, except_values: [10, 11] },
|
92
|
-
tests: [
|
93
|
-
{ value: 'invalid-type1', rc: 400, body: { error: 'type is invalid' }.to_json },
|
94
|
-
{ value: 11, rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
95
|
-
{ value: '11', rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
96
|
-
{ value: '3', rc: 200, body: { type: 3 }.to_json },
|
97
|
-
{ value: 3, rc: 200, body: { type: 3 }.to_json }
|
98
|
-
]
|
99
|
-
},
|
100
|
-
opt_except_type_coerce_default: {
|
101
|
-
optional: { type: Integer, except_values: [10, 11], default: 12 },
|
102
|
-
tests: [
|
103
|
-
{ value: 'invalid-type1', rc: 400, body: { error: 'type is invalid' }.to_json },
|
104
|
-
{ value: 10, rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
105
|
-
{ value: '3', rc: 200, body: { type: 3 }.to_json },
|
106
|
-
{ value: 3, rc: 200, body: { type: 3 }.to_json },
|
107
|
-
{ rc: 200, body: { type: 12 }.to_json }
|
108
|
-
]
|
109
|
-
},
|
110
|
-
opt_except_array_type_coerce_default: {
|
111
|
-
optional: { type: Array[Integer], except_values: [10, 11], default: 12 },
|
112
|
-
tests: [
|
113
|
-
{ value: 'invalid-type1', rc: 400, body: { error: 'type is invalid' }.to_json },
|
114
|
-
{ value: 10, rc: 400, body: { error: 'type is invalid' }.to_json },
|
115
|
-
{ value: [10], rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
116
|
-
{ value: ['3'], rc: 200, body: { type: [3] }.to_json },
|
117
|
-
{ value: [3], rc: 200, body: { type: [3] }.to_json },
|
118
|
-
{ rc: 200, body: { type: 12 }.to_json }
|
119
|
-
]
|
120
|
-
},
|
121
|
-
req_except_range: {
|
122
|
-
optional: { type: Integer, except_values: 10..12 },
|
123
|
-
tests: [
|
124
|
-
{ value: 11, rc: 400, body: { error: 'type has a value not allowed' }.to_json },
|
125
|
-
{ value: 13, rc: 200, body: { type: 13 }.to_json }
|
126
|
-
]
|
127
|
-
}
|
128
|
-
}.freeze
|
129
|
-
|
130
|
-
module ExceptValidatorSpec
|
131
|
-
class API < Grape::API
|
132
|
-
default_format :json
|
133
|
-
|
134
|
-
TEST_CASES.each_with_index do |(k, v), _i|
|
135
|
-
params do
|
136
|
-
requires :type, v[:requires] if v.key? :requires
|
137
|
-
optional :type, v[:optional] if v.key? :optional
|
138
|
-
end
|
139
|
-
get k do
|
140
|
-
{ type: params[:type] }
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
it 'raises IncompatibleOptionValues on a default value in exclude' do
|
148
|
-
subject = Class.new(Grape::API)
|
149
|
-
expect do
|
150
|
-
subject.params do
|
151
|
-
optional :type, except_values: ValidationsSpec::ExceptValuesModel.excepts,
|
152
|
-
default: ValidationsSpec::ExceptValuesModel.excepts.sample
|
153
|
-
end
|
154
|
-
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
155
|
-
end
|
156
|
-
|
157
|
-
it 'raises IncompatibleOptionValues when a default array has excluded values' do
|
158
|
-
subject = Class.new(Grape::API)
|
159
|
-
expect do
|
160
|
-
subject.params do
|
161
|
-
optional :type, type: Array[Integer],
|
162
|
-
except_values: 10..12,
|
163
|
-
default: [8, 9, 10]
|
164
|
-
end
|
165
|
-
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
166
|
-
end
|
167
|
-
|
168
|
-
it 'raises IncompatibleOptionValues when type is incompatible with values array' do
|
169
|
-
subject = Class.new(Grape::API)
|
170
|
-
expect do
|
171
|
-
subject.params { optional :type, except_values: %w[valid-type1 valid-type2 valid-type3], type: Symbol }
|
172
|
-
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
173
|
-
end
|
174
|
-
|
175
|
-
def app
|
176
|
-
ValidationsSpec::ExceptValidatorSpec::API
|
177
|
-
end
|
178
|
-
|
179
|
-
ValidationsSpec::TEST_CASES.each_with_index do |(k, v), i|
|
180
|
-
v[:tests].each do |t|
|
181
|
-
it "#{i}: #{k} - #{t[:value]}" do
|
182
|
-
ValidationsSpec::ExceptValuesModel.excepts = v[:add_excepts] if v.key? :add_excepts
|
183
|
-
body = {}
|
184
|
-
body[:type] = t[:value] if t.key? :value
|
185
|
-
get k.to_s, **body
|
186
|
-
expect(last_response.status).to eq t[:rc]
|
187
|
-
expect(last_response.body).to eq t[:body]
|
188
|
-
ValidationsSpec::ExceptValuesModel.excepts = nil
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
@@ -1,214 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Grape::Validations::Validators::MutualExclusionValidator do
|
4
|
-
let_it_be(:app) do
|
5
|
-
Class.new(Grape::API) do
|
6
|
-
rescue_from Grape::Exceptions::ValidationErrors do |e|
|
7
|
-
error!(e.errors.transform_keys! { |key| key.join(',') }, 400)
|
8
|
-
end
|
9
|
-
|
10
|
-
params do
|
11
|
-
optional :beer
|
12
|
-
optional :wine
|
13
|
-
optional :grapefruit
|
14
|
-
mutually_exclusive :beer, :wine, :grapefruit
|
15
|
-
end
|
16
|
-
post do
|
17
|
-
end
|
18
|
-
|
19
|
-
params do
|
20
|
-
optional :beer
|
21
|
-
optional :wine
|
22
|
-
optional :grapefruit
|
23
|
-
optional :other
|
24
|
-
mutually_exclusive :beer, :wine, :grapefruit
|
25
|
-
end
|
26
|
-
post 'mixed-params' do
|
27
|
-
end
|
28
|
-
|
29
|
-
params do
|
30
|
-
optional :beer
|
31
|
-
optional :wine
|
32
|
-
optional :grapefruit
|
33
|
-
mutually_exclusive :beer, :wine, :grapefruit, message: 'you should not mix beer and wine'
|
34
|
-
end
|
35
|
-
post '/custom-message' do
|
36
|
-
end
|
37
|
-
|
38
|
-
params do
|
39
|
-
requires :item, type: Hash do
|
40
|
-
optional :beer
|
41
|
-
optional :wine
|
42
|
-
optional :grapefruit
|
43
|
-
mutually_exclusive :beer, :wine, :grapefruit
|
44
|
-
end
|
45
|
-
end
|
46
|
-
post '/nested-hash' do
|
47
|
-
end
|
48
|
-
|
49
|
-
params do
|
50
|
-
optional :item, type: Hash do
|
51
|
-
optional :beer
|
52
|
-
optional :wine
|
53
|
-
optional :grapefruit
|
54
|
-
mutually_exclusive :beer, :wine, :grapefruit
|
55
|
-
end
|
56
|
-
end
|
57
|
-
post '/nested-optional-hash' do
|
58
|
-
end
|
59
|
-
|
60
|
-
params do
|
61
|
-
requires :items, type: Array do
|
62
|
-
optional :beer
|
63
|
-
optional :wine
|
64
|
-
optional :grapefruit
|
65
|
-
mutually_exclusive :beer, :wine, :grapefruit
|
66
|
-
end
|
67
|
-
end
|
68
|
-
post '/nested-array' do
|
69
|
-
end
|
70
|
-
|
71
|
-
params do
|
72
|
-
requires :items, type: Array do
|
73
|
-
requires :nested_items, type: Array do
|
74
|
-
optional :beer, :wine, :grapefruit, type: Grape::API::Boolean
|
75
|
-
mutually_exclusive :beer, :wine, :grapefruit
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
post '/deeply-nested-array' do
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
describe '#validate!' do
|
85
|
-
subject(:validate) { post path, params }
|
86
|
-
|
87
|
-
context 'when all mutually exclusive params are present' do
|
88
|
-
let(:path) { '/' }
|
89
|
-
let(:params) { { beer: true, wine: true, grapefruit: true } }
|
90
|
-
|
91
|
-
it 'returns a validation error' do
|
92
|
-
validate
|
93
|
-
expect(last_response.status).to eq 400
|
94
|
-
expect(JSON.parse(last_response.body)).to eq(
|
95
|
-
'beer,wine,grapefruit' => ['are mutually exclusive']
|
96
|
-
)
|
97
|
-
end
|
98
|
-
|
99
|
-
context 'mixed with other params' do
|
100
|
-
let(:path) { '/mixed-params' }
|
101
|
-
let(:params) { { beer: true, wine: true, grapefruit: true, other: true } }
|
102
|
-
|
103
|
-
it 'returns a validation error' do
|
104
|
-
validate
|
105
|
-
expect(last_response.status).to eq 400
|
106
|
-
expect(JSON.parse(last_response.body)).to eq(
|
107
|
-
'beer,wine,grapefruit' => ['are mutually exclusive']
|
108
|
-
)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context 'when a subset of mutually exclusive params are present' do
|
114
|
-
let(:path) { '/' }
|
115
|
-
let(:params) { { beer: true, grapefruit: true } }
|
116
|
-
|
117
|
-
it 'returns a validation error' do
|
118
|
-
validate
|
119
|
-
expect(last_response.status).to eq 400
|
120
|
-
expect(JSON.parse(last_response.body)).to eq(
|
121
|
-
'beer,grapefruit' => ['are mutually exclusive']
|
122
|
-
)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
context 'when custom message is specified' do
|
127
|
-
let(:path) { '/custom-message' }
|
128
|
-
let(:params) { { beer: true, wine: true } }
|
129
|
-
|
130
|
-
it 'returns a validation error' do
|
131
|
-
validate
|
132
|
-
expect(last_response.status).to eq 400
|
133
|
-
expect(JSON.parse(last_response.body)).to eq(
|
134
|
-
'beer,wine' => ['you should not mix beer and wine']
|
135
|
-
)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
context 'when no mutually exclusive params are present' do
|
140
|
-
let(:path) { '/' }
|
141
|
-
let(:params) { { beer: true, somethingelse: true } }
|
142
|
-
|
143
|
-
it 'does not return a validation error' do
|
144
|
-
validate
|
145
|
-
expect(last_response.status).to eq 201
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
context 'when mutually exclusive params are nested inside required hash' do
|
150
|
-
let(:path) { '/nested-hash' }
|
151
|
-
let(:params) { { item: { beer: true, wine: true } } }
|
152
|
-
|
153
|
-
it 'returns a validation error with full names of the params' do
|
154
|
-
validate
|
155
|
-
expect(last_response.status).to eq 400
|
156
|
-
expect(JSON.parse(last_response.body)).to eq(
|
157
|
-
'item[beer],item[wine]' => ['are mutually exclusive']
|
158
|
-
)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
context 'when mutually exclusive params are nested inside optional hash' do
|
163
|
-
let(:path) { '/nested-optional-hash' }
|
164
|
-
|
165
|
-
context 'when params are passed' do
|
166
|
-
let(:params) { { item: { beer: true, wine: true } } }
|
167
|
-
|
168
|
-
it 'returns a validation error with full names of the params' do
|
169
|
-
validate
|
170
|
-
expect(last_response.status).to eq 400
|
171
|
-
expect(JSON.parse(last_response.body)).to eq(
|
172
|
-
'item[beer],item[wine]' => ['are mutually exclusive']
|
173
|
-
)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
context 'when params are empty' do
|
178
|
-
let(:params) { {} }
|
179
|
-
|
180
|
-
it 'does not return a validation error' do
|
181
|
-
validate
|
182
|
-
expect(last_response.status).to eq 201
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
context 'when mutually exclusive params are nested inside array' do
|
188
|
-
let(:path) { '/nested-array' }
|
189
|
-
let(:params) { { items: [{ beer: true, wine: true }, { wine: true, grapefruit: true }] } }
|
190
|
-
|
191
|
-
it 'returns a validation error with full names of the params' do
|
192
|
-
validate
|
193
|
-
expect(last_response.status).to eq 400
|
194
|
-
expect(JSON.parse(last_response.body)).to eq(
|
195
|
-
'items[0][beer],items[0][wine]' => ['are mutually exclusive'],
|
196
|
-
'items[1][wine],items[1][grapefruit]' => ['are mutually exclusive']
|
197
|
-
)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
context 'when mutually exclusive params are deeply nested' do
|
202
|
-
let(:path) { '/deeply-nested-array' }
|
203
|
-
let(:params) { { items: [{ nested_items: [{ beer: true, wine: true }] }] } }
|
204
|
-
|
205
|
-
it 'returns a validation error with full names of the params' do
|
206
|
-
validate
|
207
|
-
expect(last_response.status).to eq 400
|
208
|
-
expect(JSON.parse(last_response.body)).to eq(
|
209
|
-
'items[0][nested_items][0][beer],items[0][nested_items][0][wine]' => ['are mutually exclusive']
|
210
|
-
)
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|