grape 1.8.0 → 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 +15 -0
- data/README.md +19 -22
- data/UPGRADING.md +35 -0
- data/grape.gemspec +1 -4
- data/lib/grape/dsl/desc.rb +1 -1
- data/lib/grape/dsl/inside_route.rb +9 -9
- data/lib/grape/endpoint.rb +9 -1
- data/lib/grape/exceptions/missing_group_type.rb +1 -1
- data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
- data/lib/grape/http/headers.rb +12 -2
- data/lib/grape/middleware/auth/strategies.rb +1 -2
- data/lib/grape/middleware/error.rb +4 -4
- data/lib/grape/middleware/formatter.rb +5 -5
- data/lib/grape/railtie.rb +9 -0
- data/lib/grape/request.rb +8 -2
- data/lib/grape/router/route.rb +1 -1
- data/lib/grape/validations/validators/base.rb +1 -1
- data/lib/grape/validations/validators/values_validator.rb +2 -2
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +15 -2
- metadata +8 -243
- data/spec/grape/api/custom_validations_spec.rb +0 -213
- 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 -509
- data/spec/grape/api_spec.rb +0 -4356
- data/spec/grape/dsl/callbacks_spec.rb +0 -45
- data/spec/grape/dsl/desc_spec.rb +0 -98
- 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 -531
- 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 -225
- 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 -185
- 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 -17
- 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 -19
- 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/grape_spec.rb +0 -9
- 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 -126
- 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 -38
- data/spec/grape/validations/params_scope_spec.rb +0 -1420
- data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
- 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/base_spec.rb +0 -38
- 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 -733
- data/spec/grape/validations/validators/zh-CN.yml +0 -10
- data/spec/grape/validations_spec.rb +0 -2030
- 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/deprecated_class_examples.rb +0 -16
- 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,1420 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Grape::Validations::ParamsScope do
|
4
|
-
subject do
|
5
|
-
Class.new(Grape::API)
|
6
|
-
end
|
7
|
-
|
8
|
-
def app
|
9
|
-
subject
|
10
|
-
end
|
11
|
-
|
12
|
-
context 'when using custom types' do
|
13
|
-
module ParamsScopeSpec
|
14
|
-
class CustomType
|
15
|
-
attr_reader :value
|
16
|
-
|
17
|
-
def self.parse(value)
|
18
|
-
raise if value == 'invalid'
|
19
|
-
|
20
|
-
new(value)
|
21
|
-
end
|
22
|
-
|
23
|
-
def initialize(value)
|
24
|
-
@value = value
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'coerces the parameter via the type\'s parse method' do
|
30
|
-
subject.params do
|
31
|
-
requires :foo, type: ParamsScopeSpec::CustomType
|
32
|
-
end
|
33
|
-
subject.get('/types') { params[:foo].value }
|
34
|
-
|
35
|
-
get '/types', foo: 'valid'
|
36
|
-
expect(last_response.status).to eq(200)
|
37
|
-
expect(last_response.body).to eq('valid')
|
38
|
-
|
39
|
-
get '/types', foo: 'invalid'
|
40
|
-
expect(last_response.status).to eq(400)
|
41
|
-
expect(last_response.body).to match(/foo is invalid/)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
context 'param renaming' do
|
46
|
-
it do
|
47
|
-
subject.params do
|
48
|
-
requires :foo, as: :bar
|
49
|
-
optional :super, as: :hiper
|
50
|
-
end
|
51
|
-
subject.get('/renaming') { "#{declared(params)['bar']}-#{declared(params)['hiper']}" }
|
52
|
-
get '/renaming', foo: 'any', super: 'any2'
|
53
|
-
|
54
|
-
expect(last_response.status).to eq(200)
|
55
|
-
expect(last_response.body).to eq('any-any2')
|
56
|
-
end
|
57
|
-
|
58
|
-
it do
|
59
|
-
subject.params do
|
60
|
-
requires :foo, as: :bar, type: String, coerce_with: ->(c) { c.strip }
|
61
|
-
end
|
62
|
-
subject.get('/renaming-coerced') { "#{params['bar']}-#{params['foo']}" }
|
63
|
-
get '/renaming-coerced', foo: ' there we go '
|
64
|
-
|
65
|
-
expect(last_response.status).to eq(200)
|
66
|
-
expect(last_response.body).to eq('-there we go')
|
67
|
-
end
|
68
|
-
|
69
|
-
it do
|
70
|
-
subject.params do
|
71
|
-
requires :foo, as: :bar, allow_blank: false
|
72
|
-
end
|
73
|
-
subject.get('/renaming-not-blank') {}
|
74
|
-
get '/renaming-not-blank', foo: ''
|
75
|
-
|
76
|
-
expect(last_response.status).to eq(400)
|
77
|
-
expect(last_response.body).to eq('foo is empty')
|
78
|
-
end
|
79
|
-
|
80
|
-
it do
|
81
|
-
subject.params do
|
82
|
-
requires :foo, as: :bar, allow_blank: false
|
83
|
-
end
|
84
|
-
subject.get('/renaming-not-blank-with-value') {}
|
85
|
-
get '/renaming-not-blank-with-value', foo: 'any'
|
86
|
-
|
87
|
-
expect(last_response.status).to eq(200)
|
88
|
-
end
|
89
|
-
|
90
|
-
it do
|
91
|
-
subject.params do
|
92
|
-
requires :foo, as: :baz, type: Hash do
|
93
|
-
requires :bar, as: :qux
|
94
|
-
end
|
95
|
-
end
|
96
|
-
subject.get('/nested-renaming') { declared(params).to_json }
|
97
|
-
get '/nested-renaming', foo: { bar: 'any' }
|
98
|
-
|
99
|
-
expect(last_response.status).to eq(200)
|
100
|
-
expect(last_response.body).to eq('{"baz":{"qux":"any"}}')
|
101
|
-
end
|
102
|
-
|
103
|
-
it 'renaming can be defined before default' do
|
104
|
-
subject.params do
|
105
|
-
optional :foo, as: :bar, default: 'before'
|
106
|
-
end
|
107
|
-
subject.get('/rename-before-default') { declared(params)[:bar] }
|
108
|
-
get '/rename-before-default'
|
109
|
-
|
110
|
-
expect(last_response.status).to eq(200)
|
111
|
-
expect(last_response.body).to eq('before')
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'renaming can be defined after default' do
|
115
|
-
subject.params do
|
116
|
-
optional :foo, default: 'after', as: :bar
|
117
|
-
end
|
118
|
-
subject.get('/rename-after-default') { declared(params)[:bar] }
|
119
|
-
get '/rename-after-default'
|
120
|
-
|
121
|
-
expect(last_response.status).to eq(200)
|
122
|
-
expect(last_response.body).to eq('after')
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
context 'array without coerce type explicitly given' do
|
127
|
-
it 'sets the type based on first element' do
|
128
|
-
subject.params do
|
129
|
-
requires :periods, type: Array, values: -> { %w[day month] }
|
130
|
-
end
|
131
|
-
subject.get('/required') { 'required works' }
|
132
|
-
|
133
|
-
get '/required', periods: %w[day month]
|
134
|
-
expect(last_response.status).to eq(200)
|
135
|
-
expect(last_response.body).to eq('required works')
|
136
|
-
end
|
137
|
-
|
138
|
-
it 'fails to call API without Array type' do
|
139
|
-
subject.params do
|
140
|
-
requires :periods, type: Array, values: -> { %w[day month] }
|
141
|
-
end
|
142
|
-
subject.get('/required') { 'required works' }
|
143
|
-
|
144
|
-
get '/required', periods: 'day'
|
145
|
-
expect(last_response.status).to eq(400)
|
146
|
-
expect(last_response.body).to eq('periods is invalid')
|
147
|
-
end
|
148
|
-
|
149
|
-
it 'raises exception when values are of different type' do
|
150
|
-
expect do
|
151
|
-
subject.params { requires :numbers, type: Array, values: [1, 'definitely not a number', 3] }
|
152
|
-
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
153
|
-
end
|
154
|
-
|
155
|
-
it 'raises exception when range values have different endpoint types' do
|
156
|
-
expect do
|
157
|
-
subject.params { requires :numbers, type: Array, values: 0.0..10 }
|
158
|
-
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
context 'coercing values validation with proc' do
|
163
|
-
it 'allows the proc to pass validation without checking' do
|
164
|
-
subject.params { requires :numbers, type: Integer, values: -> { [0, 1, 2] } }
|
165
|
-
|
166
|
-
subject.post('/required') { 'coercion with proc works' }
|
167
|
-
post '/required', numbers: '1'
|
168
|
-
expect(last_response.status).to eq(201)
|
169
|
-
expect(last_response.body).to eq('coercion with proc works')
|
170
|
-
end
|
171
|
-
|
172
|
-
it 'allows the proc to pass validation without checking in value' do
|
173
|
-
subject.params { requires :numbers, type: Integer, values: { value: -> { [0, 1, 2] } } }
|
174
|
-
|
175
|
-
subject.post('/required') { 'coercion with proc works' }
|
176
|
-
post '/required', numbers: '1'
|
177
|
-
expect(last_response.status).to eq(201)
|
178
|
-
expect(last_response.body).to eq('coercion with proc works')
|
179
|
-
end
|
180
|
-
|
181
|
-
it 'allows the proc to pass validation without checking in except' do
|
182
|
-
subject.params { requires :numbers, type: Integer, values: { except: -> { [0, 1, 2] } } }
|
183
|
-
|
184
|
-
subject.post('/required') { 'coercion with proc works' }
|
185
|
-
post '/required', numbers: '10'
|
186
|
-
expect(last_response.status).to eq(201)
|
187
|
-
expect(last_response.body).to eq('coercion with proc works')
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
context 'with range values' do
|
192
|
-
context "when left range endpoint isn't #kind_of? the type" do
|
193
|
-
it 'raises exception' do
|
194
|
-
expect do
|
195
|
-
subject.params { requires :latitude, type: Integer, values: -90.0..90 }
|
196
|
-
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
context "when right range endpoint isn't #kind_of? the type" do
|
201
|
-
it 'raises exception' do
|
202
|
-
expect do
|
203
|
-
subject.params { requires :latitude, type: Integer, values: -90..90.0 }
|
204
|
-
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
context 'when the default is an array' do
|
209
|
-
context 'and is the entire range of allowed values' do
|
210
|
-
it 'does not raise an exception' do
|
211
|
-
expect do
|
212
|
-
subject.params { optional :numbers, type: Array[Integer], values: 0..2, default: 0..2 }
|
213
|
-
end.not_to raise_error
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
context 'and is a subset of allowed values' do
|
218
|
-
it 'does not raise an exception' do
|
219
|
-
expect do
|
220
|
-
subject.params { optional :numbers, type: Array[Integer], values: [0, 1, 2], default: [1, 0] }
|
221
|
-
end.not_to raise_error
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
context 'when both range endpoints are #kind_of? the type' do
|
227
|
-
it 'accepts values in the range' do
|
228
|
-
subject.params do
|
229
|
-
requires :letter, type: String, values: 'a'..'z'
|
230
|
-
end
|
231
|
-
subject.get('/letter') { params[:letter] }
|
232
|
-
|
233
|
-
get '/letter', letter: 'j'
|
234
|
-
expect(last_response.status).to eq(200)
|
235
|
-
expect(last_response.body).to eq('j')
|
236
|
-
end
|
237
|
-
|
238
|
-
it 'rejects values outside the range' do
|
239
|
-
subject.params do
|
240
|
-
requires :letter, type: String, values: 'a'..'z'
|
241
|
-
end
|
242
|
-
subject.get('/letter') { params[:letter] }
|
243
|
-
|
244
|
-
get '/letter', letter: 'J'
|
245
|
-
expect(last_response.status).to eq(400)
|
246
|
-
expect(last_response.body).to eq('letter does not have a valid value')
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
context 'parameters in group' do
|
252
|
-
it 'errors when no type is provided' do
|
253
|
-
expect do
|
254
|
-
subject.params do
|
255
|
-
group :a do
|
256
|
-
requires :b
|
257
|
-
end
|
258
|
-
end
|
259
|
-
end.to raise_error Grape::Exceptions::MissingGroupType
|
260
|
-
|
261
|
-
expect do
|
262
|
-
subject.params do
|
263
|
-
optional :a do
|
264
|
-
requires :b
|
265
|
-
end
|
266
|
-
end
|
267
|
-
end.to raise_error Grape::Exceptions::MissingGroupType
|
268
|
-
end
|
269
|
-
|
270
|
-
it 'allows Hash as type' do
|
271
|
-
subject.params do
|
272
|
-
group :a, type: Hash do
|
273
|
-
requires :b
|
274
|
-
end
|
275
|
-
end
|
276
|
-
subject.get('/group') { 'group works' }
|
277
|
-
get '/group', a: { b: true }
|
278
|
-
expect(last_response.status).to eq(200)
|
279
|
-
expect(last_response.body).to eq('group works')
|
280
|
-
|
281
|
-
subject.params do
|
282
|
-
optional :a, type: Hash do
|
283
|
-
requires :b
|
284
|
-
end
|
285
|
-
end
|
286
|
-
get '/optional_type_hash'
|
287
|
-
end
|
288
|
-
|
289
|
-
it 'allows Array as type' do
|
290
|
-
subject.params do
|
291
|
-
group :a, type: Array do
|
292
|
-
requires :b
|
293
|
-
end
|
294
|
-
end
|
295
|
-
subject.get('/group') { 'group works' }
|
296
|
-
get '/group', a: [{ b: true }]
|
297
|
-
expect(last_response.status).to eq(200)
|
298
|
-
expect(last_response.body).to eq('group works')
|
299
|
-
|
300
|
-
subject.params do
|
301
|
-
optional :a, type: Array do
|
302
|
-
requires :b
|
303
|
-
end
|
304
|
-
end
|
305
|
-
get '/optional_type_array'
|
306
|
-
end
|
307
|
-
|
308
|
-
it 'handles missing optional Array type' do
|
309
|
-
subject.params do
|
310
|
-
optional :a, type: Array do
|
311
|
-
requires :b
|
312
|
-
end
|
313
|
-
end
|
314
|
-
subject.get('/test') { declared(params).to_json }
|
315
|
-
get '/test'
|
316
|
-
expect(last_response.status).to eq(200)
|
317
|
-
expect(last_response.body).to eq('{"a":[]}')
|
318
|
-
end
|
319
|
-
|
320
|
-
it 'errors with an unsupported type' do
|
321
|
-
expect do
|
322
|
-
subject.params do
|
323
|
-
group :a, type: Set do
|
324
|
-
requires :b
|
325
|
-
end
|
326
|
-
end
|
327
|
-
end.to raise_error Grape::Exceptions::UnsupportedGroupType
|
328
|
-
|
329
|
-
expect do
|
330
|
-
subject.params do
|
331
|
-
optional :a, type: Set do
|
332
|
-
requires :b
|
333
|
-
end
|
334
|
-
end
|
335
|
-
end.to raise_error Grape::Exceptions::UnsupportedGroupType
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
context 'when validations are dependent on a parameter' do
|
340
|
-
before do
|
341
|
-
subject.params do
|
342
|
-
optional :a
|
343
|
-
given :a do
|
344
|
-
requires :b
|
345
|
-
end
|
346
|
-
end
|
347
|
-
subject.get('/test') { declared(params).to_json }
|
348
|
-
end
|
349
|
-
|
350
|
-
it 'applies the validations only if the parameter is present' do
|
351
|
-
get '/test'
|
352
|
-
expect(last_response.status).to eq(200)
|
353
|
-
|
354
|
-
get '/test', a: true
|
355
|
-
expect(last_response.status).to eq(400)
|
356
|
-
expect(last_response.body).to eq('b is missing')
|
357
|
-
|
358
|
-
get '/test', a: true, b: true
|
359
|
-
expect(last_response.status).to eq(200)
|
360
|
-
end
|
361
|
-
|
362
|
-
it 'applies the validations of multiple parameters' do
|
363
|
-
subject.params do
|
364
|
-
optional :a, :b
|
365
|
-
given :a, :b do
|
366
|
-
requires :c
|
367
|
-
end
|
368
|
-
end
|
369
|
-
subject.get('/multiple') { declared(params).to_json }
|
370
|
-
|
371
|
-
get '/multiple'
|
372
|
-
expect(last_response.status).to eq(200)
|
373
|
-
|
374
|
-
get '/multiple', a: true
|
375
|
-
expect(last_response.status).to eq(200)
|
376
|
-
|
377
|
-
get '/multiple', b: true
|
378
|
-
expect(last_response.status).to eq(200)
|
379
|
-
|
380
|
-
get '/multiple', a: true, b: true
|
381
|
-
expect(last_response.status).to eq(400)
|
382
|
-
expect(last_response.body).to eq('c is missing')
|
383
|
-
|
384
|
-
get '/multiple', a: true, b: true, c: true
|
385
|
-
expect(last_response.status).to eq(200)
|
386
|
-
end
|
387
|
-
|
388
|
-
it 'applies only the appropriate validation' do
|
389
|
-
subject.params do
|
390
|
-
optional :a
|
391
|
-
optional :b
|
392
|
-
mutually_exclusive :a, :b
|
393
|
-
given :a do
|
394
|
-
requires :c, type: String
|
395
|
-
end
|
396
|
-
given :b do
|
397
|
-
requires :c, type: Integer
|
398
|
-
end
|
399
|
-
end
|
400
|
-
subject.get('/multiple') { declared(params).to_json }
|
401
|
-
|
402
|
-
get '/multiple'
|
403
|
-
expect(last_response.status).to eq(200)
|
404
|
-
|
405
|
-
get '/multiple', a: true, c: 'test'
|
406
|
-
expect(last_response.status).to eq(200)
|
407
|
-
expect(JSON.parse(last_response.body).symbolize_keys).to eq a: 'true', b: nil, c: 'test'
|
408
|
-
|
409
|
-
get '/multiple', b: true, c: '3'
|
410
|
-
expect(last_response.status).to eq(200)
|
411
|
-
expect(JSON.parse(last_response.body).symbolize_keys).to eq a: nil, b: 'true', c: 3
|
412
|
-
|
413
|
-
get '/multiple', a: true
|
414
|
-
expect(last_response.status).to eq(400)
|
415
|
-
expect(last_response.body).to eq('c is missing')
|
416
|
-
|
417
|
-
get '/multiple', b: true
|
418
|
-
expect(last_response.status).to eq(400)
|
419
|
-
expect(last_response.body).to eq('c is missing')
|
420
|
-
|
421
|
-
get '/multiple', a: true, b: true, c: 'test'
|
422
|
-
expect(last_response.status).to eq(400)
|
423
|
-
expect(last_response.body).to eq('a, b are mutually exclusive, c is invalid')
|
424
|
-
end
|
425
|
-
|
426
|
-
it 'raises an error if the dependent parameter was never specified' do
|
427
|
-
expect do
|
428
|
-
subject.params do
|
429
|
-
given :c do
|
430
|
-
end
|
431
|
-
end
|
432
|
-
end.to raise_error(Grape::Exceptions::UnknownParameter)
|
433
|
-
end
|
434
|
-
|
435
|
-
it 'does not raise an error if the dependent parameter is a Hash' do
|
436
|
-
expect do
|
437
|
-
subject.params do
|
438
|
-
optional :a, type: Hash do
|
439
|
-
requires :b
|
440
|
-
end
|
441
|
-
given :a do
|
442
|
-
requires :c
|
443
|
-
end
|
444
|
-
end
|
445
|
-
end.not_to raise_error
|
446
|
-
end
|
447
|
-
|
448
|
-
it 'does not raise an error if when using nested given' do
|
449
|
-
expect do
|
450
|
-
subject.params do
|
451
|
-
optional :a, type: Hash do
|
452
|
-
requires :b
|
453
|
-
end
|
454
|
-
given :a do
|
455
|
-
requires :c
|
456
|
-
given :c do
|
457
|
-
requires :d
|
458
|
-
end
|
459
|
-
end
|
460
|
-
end
|
461
|
-
end.not_to raise_error
|
462
|
-
end
|
463
|
-
|
464
|
-
it 'allows nested dependent parameters' do
|
465
|
-
subject.params do
|
466
|
-
optional :a
|
467
|
-
given a: ->(val) { val == 'a' } do
|
468
|
-
optional :b
|
469
|
-
given b: ->(val) { val == 'b' } do
|
470
|
-
optional :c
|
471
|
-
given c: ->(val) { val == 'c' } do
|
472
|
-
requires :d
|
473
|
-
end
|
474
|
-
end
|
475
|
-
end
|
476
|
-
end
|
477
|
-
subject.get('/') { declared(params).to_json }
|
478
|
-
|
479
|
-
get '/'
|
480
|
-
expect(last_response.status).to eq 200
|
481
|
-
|
482
|
-
get '/', a: 'a', b: 'b', c: 'c'
|
483
|
-
expect(last_response.status).to eq 400
|
484
|
-
expect(last_response.body).to eq 'd is missing'
|
485
|
-
|
486
|
-
get '/', a: 'a', b: 'b', c: 'c', d: 'd'
|
487
|
-
expect(last_response.status).to eq 200
|
488
|
-
expect(last_response.body).to eq({ a: 'a', b: 'b', c: 'c', d: 'd' }.to_json)
|
489
|
-
end
|
490
|
-
|
491
|
-
it 'allows renaming of dependent parameters' do
|
492
|
-
subject.params do
|
493
|
-
optional :a
|
494
|
-
given :a do
|
495
|
-
requires :b, as: :c
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
subject.get('/multiple') { declared(params).to_json }
|
500
|
-
|
501
|
-
get '/multiple', a: 'a', b: 'b'
|
502
|
-
|
503
|
-
body = JSON.parse(last_response.body)
|
504
|
-
|
505
|
-
expect(body.keys).to include('c')
|
506
|
-
expect(body.keys).not_to include('b')
|
507
|
-
end
|
508
|
-
|
509
|
-
it 'allows renaming of dependent on parameter' do
|
510
|
-
subject.params do
|
511
|
-
optional :a, as: :b
|
512
|
-
given a: ->(val) { val == 'x' } do
|
513
|
-
requires :c
|
514
|
-
end
|
515
|
-
end
|
516
|
-
subject.get('/') { declared(params) }
|
517
|
-
|
518
|
-
get '/', a: 'x'
|
519
|
-
expect(last_response.status).to eq 400
|
520
|
-
expect(last_response.body).to eq 'c is missing'
|
521
|
-
|
522
|
-
get '/', a: 'y'
|
523
|
-
expect(last_response.status).to eq 200
|
524
|
-
end
|
525
|
-
|
526
|
-
it 'does not raise if the dependent parameter is not the renamed one' do
|
527
|
-
expect do
|
528
|
-
subject.params do
|
529
|
-
optional :a, as: :b
|
530
|
-
given :a do
|
531
|
-
requires :c
|
532
|
-
end
|
533
|
-
end
|
534
|
-
end.not_to raise_error
|
535
|
-
end
|
536
|
-
|
537
|
-
it 'raises an error if the dependent parameter is the renamed one' do
|
538
|
-
expect do
|
539
|
-
subject.params do
|
540
|
-
optional :a, as: :b
|
541
|
-
given :b do
|
542
|
-
requires :c
|
543
|
-
end
|
544
|
-
end
|
545
|
-
end.to raise_error(Grape::Exceptions::UnknownParameter)
|
546
|
-
end
|
547
|
-
|
548
|
-
it 'does not validate nested requires when given is false' do
|
549
|
-
subject.params do
|
550
|
-
requires :a, type: String, allow_blank: false, values: %w[x y z]
|
551
|
-
given a: ->(val) { val == 'x' } do
|
552
|
-
requires :inner1, type: Hash, allow_blank: false do
|
553
|
-
requires :foo, type: Integer, allow_blank: false
|
554
|
-
end
|
555
|
-
end
|
556
|
-
given a: ->(val) { val == 'y' } do
|
557
|
-
requires :inner2, type: Hash, allow_blank: false do
|
558
|
-
requires :bar, type: Integer, allow_blank: false
|
559
|
-
requires :baz, type: Array, allow_blank: false do
|
560
|
-
requires :baz_category, type: String, allow_blank: false
|
561
|
-
end
|
562
|
-
end
|
563
|
-
end
|
564
|
-
given a: ->(val) { val == 'z' } do
|
565
|
-
requires :inner3, type: Array, allow_blank: false do
|
566
|
-
requires :bar, type: Integer, allow_blank: false
|
567
|
-
requires :baz, type: Array, allow_blank: false do
|
568
|
-
requires :baz_category, type: String, allow_blank: false
|
569
|
-
end
|
570
|
-
end
|
571
|
-
end
|
572
|
-
end
|
573
|
-
subject.get('/varying') { declared(params).to_json }
|
574
|
-
|
575
|
-
get '/varying', a: 'x', inner1: { foo: 1 }
|
576
|
-
expect(last_response.status).to eq(200)
|
577
|
-
|
578
|
-
get '/varying', a: 'y', inner2: { bar: 2, baz: [{ baz_category: 'barstools' }] }
|
579
|
-
expect(last_response.status).to eq(200)
|
580
|
-
|
581
|
-
get '/varying', a: 'y', inner2: { bar: 2, baz: [{ unrelated: 'yep' }] }
|
582
|
-
expect(last_response.status).to eq(400)
|
583
|
-
|
584
|
-
get '/varying', a: 'z', inner3: [{ bar: 3, baz: [{ baz_category: 'barstools' }] }]
|
585
|
-
expect(last_response.status).to eq(200)
|
586
|
-
end
|
587
|
-
|
588
|
-
it 'detect unmet nested dependency' do
|
589
|
-
subject.params do
|
590
|
-
requires :a, type: String, allow_blank: false, values: %w[x y z]
|
591
|
-
given a: ->(val) { val == 'z' } do
|
592
|
-
requires :inner3, type: Array, allow_blank: false do
|
593
|
-
requires :bar, type: String, allow_blank: false
|
594
|
-
given bar: ->(val) { val == 'b' } do
|
595
|
-
requires :baz, type: Array do
|
596
|
-
optional :baz_category, type: String
|
597
|
-
end
|
598
|
-
end
|
599
|
-
given bar: ->(val) { val == 'c' } do
|
600
|
-
requires :baz, type: Array do
|
601
|
-
requires :baz_category, type: String
|
602
|
-
end
|
603
|
-
end
|
604
|
-
end
|
605
|
-
end
|
606
|
-
end
|
607
|
-
subject.get('/nested-dependency') { declared(params).to_json }
|
608
|
-
|
609
|
-
get '/nested-dependency', a: 'z', inner3: [{ bar: 'c', baz: [{ unrelated: 'nope' }] }]
|
610
|
-
expect(last_response.status).to eq(400)
|
611
|
-
expect(last_response.body).to eq 'inner3[0][baz][0][baz_category] is missing'
|
612
|
-
end
|
613
|
-
|
614
|
-
it 'includes the parameter within #declared(params)' do
|
615
|
-
get '/test', a: true, b: true
|
616
|
-
|
617
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'true', 'b' => 'true')
|
618
|
-
end
|
619
|
-
|
620
|
-
it 'returns a sensible error message within a nested context' do
|
621
|
-
subject.params do
|
622
|
-
requires :bar, type: Hash do
|
623
|
-
optional :a
|
624
|
-
given :a do
|
625
|
-
requires :b
|
626
|
-
end
|
627
|
-
end
|
628
|
-
end
|
629
|
-
subject.get('/nested') { 'worked' }
|
630
|
-
|
631
|
-
get '/nested', bar: { a: true }
|
632
|
-
expect(last_response.status).to eq(400)
|
633
|
-
expect(last_response.body).to eq('bar[b] is missing')
|
634
|
-
end
|
635
|
-
|
636
|
-
it 'includes the nested parameter within #declared(params)' do
|
637
|
-
subject.params do
|
638
|
-
requires :bar, type: Hash do
|
639
|
-
optional :a
|
640
|
-
given :a do
|
641
|
-
requires :b
|
642
|
-
end
|
643
|
-
end
|
644
|
-
end
|
645
|
-
subject.get('/nested') { declared(params).to_json }
|
646
|
-
|
647
|
-
get '/nested', bar: { a: true, b: 'yes' }
|
648
|
-
expect(JSON.parse(last_response.body)).to eq('bar' => { 'a' => 'true', 'b' => 'yes' })
|
649
|
-
end
|
650
|
-
|
651
|
-
it 'includes level 2 nested parameters outside the given within #declared(params)' do
|
652
|
-
subject.params do
|
653
|
-
requires :bar, type: Hash do
|
654
|
-
optional :a
|
655
|
-
given :a do
|
656
|
-
requires :c, type: Hash do
|
657
|
-
requires :b
|
658
|
-
end
|
659
|
-
end
|
660
|
-
end
|
661
|
-
end
|
662
|
-
subject.get('/nested') { declared(params).to_json }
|
663
|
-
|
664
|
-
get '/nested', bar: { a: true, c: { b: 'yes' } }
|
665
|
-
expect(JSON.parse(last_response.body)).to eq('bar' => { 'a' => 'true', 'c' => { 'b' => 'yes' } })
|
666
|
-
end
|
667
|
-
|
668
|
-
context 'when the dependent parameter is not present #declared(params)' do
|
669
|
-
context 'lateral parameter' do
|
670
|
-
before do
|
671
|
-
[true, false].each do |evaluate_given|
|
672
|
-
subject.params do
|
673
|
-
optional :a
|
674
|
-
given :a do
|
675
|
-
optional :b
|
676
|
-
end
|
677
|
-
end
|
678
|
-
subject.get("/evaluate_given_#{evaluate_given}") { declared(params, evaluate_given: evaluate_given).to_json }
|
679
|
-
end
|
680
|
-
end
|
681
|
-
|
682
|
-
it 'evaluate_given_false' do
|
683
|
-
get '/evaluate_given_false', b: 'b'
|
684
|
-
expect(JSON.parse(last_response.body)).to eq('a' => nil, 'b' => 'b')
|
685
|
-
end
|
686
|
-
|
687
|
-
it 'evaluate_given_true' do
|
688
|
-
get '/evaluate_given_true', b: 'b'
|
689
|
-
expect(JSON.parse(last_response.body)).to eq('a' => nil)
|
690
|
-
end
|
691
|
-
end
|
692
|
-
|
693
|
-
context 'lateral hash parameter' do
|
694
|
-
before do
|
695
|
-
[true, false].each do |evaluate_given|
|
696
|
-
subject.params do
|
697
|
-
optional :a, values: %w[x y]
|
698
|
-
given a: ->(a) { a == 'x' } do
|
699
|
-
optional :b, type: Hash do
|
700
|
-
optional :c
|
701
|
-
end
|
702
|
-
optional :e
|
703
|
-
end
|
704
|
-
given a: ->(a) { a == 'y' } do
|
705
|
-
optional :b, type: Hash do
|
706
|
-
optional :d
|
707
|
-
end
|
708
|
-
optional :f
|
709
|
-
end
|
710
|
-
end
|
711
|
-
subject.get("/evaluate_given_#{evaluate_given}") { declared(params, evaluate_given: evaluate_given).to_json }
|
712
|
-
end
|
713
|
-
end
|
714
|
-
|
715
|
-
it 'evaluate_given_false' do
|
716
|
-
get '/evaluate_given_false', a: 'x'
|
717
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'd' => nil }, 'e' => nil, 'f' => nil)
|
718
|
-
|
719
|
-
get '/evaluate_given_false', a: 'y'
|
720
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil }, 'e' => nil, 'f' => nil)
|
721
|
-
end
|
722
|
-
|
723
|
-
it 'evaluate_given_true' do
|
724
|
-
get '/evaluate_given_true', a: 'x'
|
725
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'c' => nil }, 'e' => nil)
|
726
|
-
|
727
|
-
get '/evaluate_given_true', a: 'y'
|
728
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil }, 'f' => nil)
|
729
|
-
end
|
730
|
-
end
|
731
|
-
|
732
|
-
context 'lateral parameter within lateral hash parameter' do
|
733
|
-
before do
|
734
|
-
[true, false].each do |evaluate_given|
|
735
|
-
subject.params do
|
736
|
-
optional :a, values: %w[x y]
|
737
|
-
given a: ->(a) { a == 'x' } do
|
738
|
-
optional :b, type: Hash do
|
739
|
-
optional :c
|
740
|
-
given :c do
|
741
|
-
optional :g
|
742
|
-
optional :e, type: Hash do
|
743
|
-
optional :h
|
744
|
-
end
|
745
|
-
end
|
746
|
-
end
|
747
|
-
end
|
748
|
-
given a: ->(a) { a == 'y' } do
|
749
|
-
optional :b, type: Hash do
|
750
|
-
optional :d
|
751
|
-
given :d do
|
752
|
-
optional :f
|
753
|
-
optional :e, type: Hash do
|
754
|
-
optional :i
|
755
|
-
end
|
756
|
-
end
|
757
|
-
end
|
758
|
-
end
|
759
|
-
end
|
760
|
-
subject.get("/evaluate_given_#{evaluate_given}") { declared(params, evaluate_given: evaluate_given).to_json }
|
761
|
-
end
|
762
|
-
end
|
763
|
-
|
764
|
-
it 'evaluate_given_false' do
|
765
|
-
get '/evaluate_given_false', a: 'x'
|
766
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'd' => nil, 'f' => nil, 'e' => { 'i' => nil } })
|
767
|
-
|
768
|
-
get '/evaluate_given_false', a: 'x', b: { c: 'c' }
|
769
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'd' => nil, 'f' => nil, 'e' => { 'i' => nil } })
|
770
|
-
|
771
|
-
get '/evaluate_given_false', a: 'y'
|
772
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil, 'f' => nil, 'e' => { 'i' => nil } })
|
773
|
-
|
774
|
-
get '/evaluate_given_false', a: 'y', b: { d: 'd' }
|
775
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => 'd', 'f' => nil, 'e' => { 'i' => nil } })
|
776
|
-
end
|
777
|
-
|
778
|
-
it 'evaluate_given_true' do
|
779
|
-
get '/evaluate_given_true', a: 'x'
|
780
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'c' => nil })
|
781
|
-
|
782
|
-
get '/evaluate_given_true', a: 'x', b: { c: 'c' }
|
783
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'c' => 'c', 'g' => nil, 'e' => { 'h' => nil } })
|
784
|
-
|
785
|
-
get '/evaluate_given_true', a: 'y'
|
786
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil })
|
787
|
-
|
788
|
-
get '/evaluate_given_true', a: 'y', b: { d: 'd' }
|
789
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => 'd', 'f' => nil, 'e' => { 'i' => nil } })
|
790
|
-
end
|
791
|
-
end
|
792
|
-
|
793
|
-
context 'lateral parameter within an array param' do
|
794
|
-
before do
|
795
|
-
[true, false].each do |evaluate_given|
|
796
|
-
subject.params do
|
797
|
-
optional :array, type: Array do
|
798
|
-
optional :a
|
799
|
-
given :a do
|
800
|
-
optional :b
|
801
|
-
end
|
802
|
-
end
|
803
|
-
end
|
804
|
-
subject.post("/evaluate_given_#{evaluate_given}") do
|
805
|
-
declared(params, evaluate_given: evaluate_given).to_json
|
806
|
-
end
|
807
|
-
end
|
808
|
-
end
|
809
|
-
|
810
|
-
it 'evaluate_given_false' do
|
811
|
-
post '/evaluate_given_false', { array: [{ b: 'b' }, { a: 'a', b: 'b' }] }.to_json, 'CONTENT_TYPE' => 'application/json'
|
812
|
-
expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => nil, 'b' => 'b' }, { 'a' => 'a', 'b' => 'b' }])
|
813
|
-
end
|
814
|
-
|
815
|
-
it 'evaluate_given_true' do
|
816
|
-
post '/evaluate_given_true', { array: [{ b: 'b' }, { a: 'a', b: 'b' }] }.to_json, 'CONTENT_TYPE' => 'application/json'
|
817
|
-
expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => nil }, { 'a' => 'a', 'b' => 'b' }])
|
818
|
-
end
|
819
|
-
end
|
820
|
-
|
821
|
-
context 'nested given parameter' do
|
822
|
-
before do
|
823
|
-
[true, false].each do |evaluate_given|
|
824
|
-
subject.params do
|
825
|
-
optional :a
|
826
|
-
optional :c
|
827
|
-
given :a do
|
828
|
-
given :c do
|
829
|
-
optional :b
|
830
|
-
end
|
831
|
-
end
|
832
|
-
end
|
833
|
-
subject.post("/evaluate_given_#{evaluate_given}") do
|
834
|
-
declared(params, evaluate_given: evaluate_given).to_json
|
835
|
-
end
|
836
|
-
end
|
837
|
-
end
|
838
|
-
|
839
|
-
it 'evaluate_given_false' do
|
840
|
-
post '/evaluate_given_false', { a: 'a', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
|
841
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => nil)
|
842
|
-
|
843
|
-
post '/evaluate_given_false', { c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
|
844
|
-
expect(JSON.parse(last_response.body)).to eq('a' => nil, 'b' => 'b', 'c' => 'c')
|
845
|
-
|
846
|
-
post '/evaluate_given_false', { a: 'a', c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
|
847
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => 'c')
|
848
|
-
end
|
849
|
-
|
850
|
-
it 'evaluate_given_true' do
|
851
|
-
post '/evaluate_given_true', { a: 'a', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
|
852
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'c' => nil)
|
853
|
-
|
854
|
-
post '/evaluate_given_true', { c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
|
855
|
-
expect(JSON.parse(last_response.body)).to eq('a' => nil, 'c' => 'c')
|
856
|
-
|
857
|
-
post '/evaluate_given_true', { a: 'a', c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
|
858
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => 'c')
|
859
|
-
end
|
860
|
-
end
|
861
|
-
|
862
|
-
context 'nested given parameter within an array param' do
|
863
|
-
before do
|
864
|
-
[true, false].each do |evaluate_given|
|
865
|
-
subject.params do
|
866
|
-
optional :array, type: Array do
|
867
|
-
optional :a
|
868
|
-
optional :c
|
869
|
-
given :a do
|
870
|
-
given :c do
|
871
|
-
optional :b
|
872
|
-
end
|
873
|
-
end
|
874
|
-
end
|
875
|
-
end
|
876
|
-
subject.post("/evaluate_given_#{evaluate_given}") do
|
877
|
-
declared(params, evaluate_given: evaluate_given).to_json
|
878
|
-
end
|
879
|
-
end
|
880
|
-
end
|
881
|
-
|
882
|
-
let :evaluate_given_params do
|
883
|
-
{
|
884
|
-
array: [
|
885
|
-
{ a: 'a', b: 'b' },
|
886
|
-
{ c: 'c', b: 'b' },
|
887
|
-
{ a: 'a', c: 'c', b: 'b' }
|
888
|
-
]
|
889
|
-
}
|
890
|
-
end
|
891
|
-
|
892
|
-
it 'evaluate_given_false' do
|
893
|
-
post '/evaluate_given_false', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
|
894
|
-
expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => 'a', 'b' => 'b', 'c' => nil }, { 'a' => nil, 'b' => 'b', 'c' => 'c' }, { 'a' => 'a', 'b' => 'b', 'c' => 'c' }])
|
895
|
-
end
|
896
|
-
|
897
|
-
it 'evaluate_given_true' do
|
898
|
-
post '/evaluate_given_true', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
|
899
|
-
expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => 'a', 'c' => nil }, { 'a' => nil, 'c' => 'c' }, { 'a' => 'a', 'b' => 'b', 'c' => 'c' }])
|
900
|
-
end
|
901
|
-
end
|
902
|
-
|
903
|
-
context 'nested given parameter within a nested given parameter within an array param' do
|
904
|
-
before do
|
905
|
-
[true, false].each do |evaluate_given|
|
906
|
-
subject.params do
|
907
|
-
optional :array, type: Array do
|
908
|
-
optional :a
|
909
|
-
optional :c
|
910
|
-
given :a do
|
911
|
-
given :c do
|
912
|
-
optional :array, type: Array do
|
913
|
-
optional :a
|
914
|
-
optional :c
|
915
|
-
given :a do
|
916
|
-
given :c do
|
917
|
-
optional :b
|
918
|
-
end
|
919
|
-
end
|
920
|
-
end
|
921
|
-
end
|
922
|
-
end
|
923
|
-
end
|
924
|
-
end
|
925
|
-
subject.post("/evaluate_given_#{evaluate_given}") do
|
926
|
-
declared(params, evaluate_given: evaluate_given).to_json
|
927
|
-
end
|
928
|
-
end
|
929
|
-
end
|
930
|
-
|
931
|
-
let :evaluate_given_params do
|
932
|
-
{
|
933
|
-
array: [{
|
934
|
-
a: 'a',
|
935
|
-
c: 'c',
|
936
|
-
array: [
|
937
|
-
{ a: 'a', b: 'b' },
|
938
|
-
{ c: 'c', b: 'b' },
|
939
|
-
{ a: 'a', c: 'c', b: 'b' }
|
940
|
-
]
|
941
|
-
}]
|
942
|
-
}
|
943
|
-
end
|
944
|
-
|
945
|
-
it 'evaluate_given_false' do
|
946
|
-
expected_response_hash = {
|
947
|
-
'array' => [{
|
948
|
-
'a' => 'a',
|
949
|
-
'c' => 'c',
|
950
|
-
'array' => [
|
951
|
-
{ 'a' => 'a', 'b' => 'b', 'c' => nil },
|
952
|
-
{ 'a' => nil, 'c' => 'c', 'b' => 'b' },
|
953
|
-
{ 'a' => 'a', 'c' => 'c', 'b' => 'b' }
|
954
|
-
]
|
955
|
-
}]
|
956
|
-
}
|
957
|
-
post '/evaluate_given_false', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
|
958
|
-
expect(JSON.parse(last_response.body)).to eq(expected_response_hash)
|
959
|
-
end
|
960
|
-
|
961
|
-
it 'evaluate_given_true' do
|
962
|
-
expected_response_hash = {
|
963
|
-
'array' => [{
|
964
|
-
'a' => 'a',
|
965
|
-
'c' => 'c',
|
966
|
-
'array' => [
|
967
|
-
{ 'a' => 'a', 'c' => nil },
|
968
|
-
{ 'a' => nil, 'c' => 'c' },
|
969
|
-
{ 'a' => 'a', 'b' => 'b', 'c' => 'c' }
|
970
|
-
]
|
971
|
-
}]
|
972
|
-
}
|
973
|
-
post '/evaluate_given_true', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
|
974
|
-
expect(JSON.parse(last_response.body)).to eq(expected_response_hash)
|
975
|
-
end
|
976
|
-
end
|
977
|
-
end
|
978
|
-
end
|
979
|
-
|
980
|
-
context 'default value in given block' do
|
981
|
-
before do
|
982
|
-
subject.params do
|
983
|
-
optional :a, values: %w[a b]
|
984
|
-
given a: ->(val) { val == 'a' } do
|
985
|
-
optional :b, default: 'default'
|
986
|
-
end
|
987
|
-
end
|
988
|
-
subject.get('/') { params.to_json }
|
989
|
-
end
|
990
|
-
|
991
|
-
context 'when dependency meets' do
|
992
|
-
it 'sets default value for dependent parameter' do
|
993
|
-
get '/', a: 'a'
|
994
|
-
expect(last_response.body).to eq({ a: 'a', b: 'default' }.to_json)
|
995
|
-
end
|
996
|
-
end
|
997
|
-
|
998
|
-
context 'when dependency does not meet' do
|
999
|
-
it 'does not set default value for dependent parameter' do
|
1000
|
-
get '/', a: 'b'
|
1001
|
-
expect(last_response.body).to eq({ a: 'b' }.to_json)
|
1002
|
-
end
|
1003
|
-
end
|
1004
|
-
end
|
1005
|
-
|
1006
|
-
context 'when validations are dependent on a parameter within an array param' do
|
1007
|
-
before do
|
1008
|
-
subject.params do
|
1009
|
-
requires :foos, type: Array do
|
1010
|
-
optional :foo
|
1011
|
-
given :foo do
|
1012
|
-
requires :bar
|
1013
|
-
end
|
1014
|
-
end
|
1015
|
-
end
|
1016
|
-
subject.get('/test') { 'ok' }
|
1017
|
-
end
|
1018
|
-
|
1019
|
-
it 'passes none Hash params' do
|
1020
|
-
get '/test', foos: ['']
|
1021
|
-
expect(last_response.status).to eq(200)
|
1022
|
-
expect(last_response.body).to eq('ok')
|
1023
|
-
end
|
1024
|
-
end
|
1025
|
-
|
1026
|
-
context 'when validations are dependent on a parameter within an array param within #declared(params).to_json' do
|
1027
|
-
before do
|
1028
|
-
subject.params do
|
1029
|
-
requires :foos, type: Array do
|
1030
|
-
optional :foo_type, :baz_type
|
1031
|
-
given :foo_type do
|
1032
|
-
requires :bar
|
1033
|
-
end
|
1034
|
-
end
|
1035
|
-
end
|
1036
|
-
subject.post('/test') { declared(params).to_json }
|
1037
|
-
end
|
1038
|
-
|
1039
|
-
it 'applies the constraint within each value' do
|
1040
|
-
post '/test',
|
1041
|
-
{ foos: [{ foo_type: 'a' }, { baz_type: 'c' }] }.to_json,
|
1042
|
-
'CONTENT_TYPE' => 'application/json'
|
1043
|
-
|
1044
|
-
expect(last_response.status).to eq(400)
|
1045
|
-
expect(last_response.body).to eq('foos[0][bar] is missing')
|
1046
|
-
end
|
1047
|
-
end
|
1048
|
-
|
1049
|
-
context 'when validations are dependent on a parameter with specific value' do
|
1050
|
-
# build test cases from all combinations of declarations and options
|
1051
|
-
a_decls = %i[optional requires]
|
1052
|
-
a_options = [{}, { values: %w[x y z] }]
|
1053
|
-
b_options = [{}, { type: String }, { allow_blank: false }, { type: String, allow_blank: false }]
|
1054
|
-
combinations = a_decls.product(a_options, b_options)
|
1055
|
-
combinations.each_with_index do |combination, i|
|
1056
|
-
a_decl, a_opts, b_opts = combination
|
1057
|
-
|
1058
|
-
context "(case #{i})" do
|
1059
|
-
before do
|
1060
|
-
# puts "a_decl: #{a_decl}, a_opts: #{a_opts}, b_opts: #{b_opts}"
|
1061
|
-
subject.params do
|
1062
|
-
send a_decl, :a, **a_opts
|
1063
|
-
given(a: ->(val) { val == 'x' }) { requires :b, **b_opts }
|
1064
|
-
given(a: ->(val) { val == 'y' }) { requires :c, **b_opts }
|
1065
|
-
end
|
1066
|
-
subject.get('/test') { declared(params).to_json }
|
1067
|
-
end
|
1068
|
-
|
1069
|
-
if a_decl == :optional
|
1070
|
-
it 'skips validation when base param is missing' do
|
1071
|
-
get '/test'
|
1072
|
-
expect(last_response.status).to eq(200)
|
1073
|
-
end
|
1074
|
-
end
|
1075
|
-
|
1076
|
-
it 'skips validation when base param does not have a specified value' do
|
1077
|
-
get '/test', a: 'z'
|
1078
|
-
expect(last_response.status).to eq(200)
|
1079
|
-
|
1080
|
-
get '/test', a: 'z', b: ''
|
1081
|
-
expect(last_response.status).to eq(200)
|
1082
|
-
end
|
1083
|
-
|
1084
|
-
it 'applies the validation when base param has the specific value' do
|
1085
|
-
get '/test', a: 'x'
|
1086
|
-
expect(last_response.status).to eq(400)
|
1087
|
-
expect(last_response.body).to include('b is missing')
|
1088
|
-
|
1089
|
-
get '/test', a: 'x', b: true
|
1090
|
-
expect(last_response.status).to eq(200)
|
1091
|
-
|
1092
|
-
get '/test', a: 'x', b: true, c: ''
|
1093
|
-
expect(last_response.status).to eq(200)
|
1094
|
-
end
|
1095
|
-
|
1096
|
-
it 'includes the parameter within #declared(params)' do
|
1097
|
-
get '/test', a: 'x', b: true
|
1098
|
-
expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => 'true', 'c' => nil)
|
1099
|
-
end
|
1100
|
-
end
|
1101
|
-
end
|
1102
|
-
end
|
1103
|
-
|
1104
|
-
it 'raises an error if the dependent parameter was never specified' do
|
1105
|
-
expect do
|
1106
|
-
subject.params do
|
1107
|
-
given :c do
|
1108
|
-
end
|
1109
|
-
end
|
1110
|
-
end.to raise_error(Grape::Exceptions::UnknownParameter)
|
1111
|
-
end
|
1112
|
-
|
1113
|
-
it 'returns a sensible error message within a nested context' do
|
1114
|
-
subject.params do
|
1115
|
-
requires :bar, type: Hash do
|
1116
|
-
optional :a
|
1117
|
-
given a: ->(val) { val == 'x' } do
|
1118
|
-
requires :b
|
1119
|
-
end
|
1120
|
-
end
|
1121
|
-
end
|
1122
|
-
subject.get('/nested') { 'worked' }
|
1123
|
-
|
1124
|
-
get '/nested', bar: { a: 'x' }
|
1125
|
-
expect(last_response.status).to eq(400)
|
1126
|
-
expect(last_response.body).to eq('bar[b] is missing')
|
1127
|
-
end
|
1128
|
-
|
1129
|
-
it 'includes the nested parameter within #declared(params)' do
|
1130
|
-
subject.params do
|
1131
|
-
requires :bar, type: Hash do
|
1132
|
-
optional :a
|
1133
|
-
given a: ->(val) { val == 'x' } do
|
1134
|
-
requires :b
|
1135
|
-
end
|
1136
|
-
end
|
1137
|
-
end
|
1138
|
-
subject.get('/nested') { declared(params).to_json }
|
1139
|
-
|
1140
|
-
get '/nested', bar: { a: 'x', b: 'yes' }
|
1141
|
-
expect(JSON.parse(last_response.body)).to eq('bar' => { 'a' => 'x', 'b' => 'yes' })
|
1142
|
-
end
|
1143
|
-
|
1144
|
-
it 'includes level 2 nested parameters outside the given within #declared(params)' do
|
1145
|
-
subject.params do
|
1146
|
-
requires :bar, type: Hash do
|
1147
|
-
optional :a
|
1148
|
-
given a: ->(val) { val == 'x' } do
|
1149
|
-
requires :c, type: Hash do
|
1150
|
-
requires :b
|
1151
|
-
end
|
1152
|
-
end
|
1153
|
-
end
|
1154
|
-
end
|
1155
|
-
subject.get('/nested') { declared(params).to_json }
|
1156
|
-
|
1157
|
-
get '/nested', bar: { a: 'x', c: { b: 'yes' } }
|
1158
|
-
expect(JSON.parse(last_response.body)).to eq('bar' => { 'a' => 'x', 'c' => { 'b' => 'yes' } })
|
1159
|
-
end
|
1160
|
-
|
1161
|
-
it 'includes deeply nested parameters within #declared(params)' do
|
1162
|
-
subject.params do
|
1163
|
-
requires :arr1, type: Array do
|
1164
|
-
requires :hash1, type: Hash do
|
1165
|
-
requires :arr2, type: Array do
|
1166
|
-
requires :hash2, type: Hash do
|
1167
|
-
requires :something, type: String
|
1168
|
-
end
|
1169
|
-
end
|
1170
|
-
end
|
1171
|
-
end
|
1172
|
-
end
|
1173
|
-
subject.get('/nested_deep') { declared(params).to_json }
|
1174
|
-
|
1175
|
-
get '/nested_deep', arr1: [{ hash1: { arr2: [{ hash2: { something: 'value' } }] } }]
|
1176
|
-
expect(last_response.status).to eq(200)
|
1177
|
-
expect(JSON.parse(last_response.body)).to eq('arr1' => [{ 'hash1' => { 'arr2' => [{ 'hash2' => { 'something' => 'value' } }] } }])
|
1178
|
-
end
|
1179
|
-
|
1180
|
-
context 'failing fast' do
|
1181
|
-
context 'when fail_fast is not defined' do
|
1182
|
-
it 'does not stop validation' do
|
1183
|
-
subject.params do
|
1184
|
-
requires :one
|
1185
|
-
requires :two
|
1186
|
-
requires :three
|
1187
|
-
end
|
1188
|
-
subject.get('/fail-fast') { declared(params).to_json }
|
1189
|
-
|
1190
|
-
get '/fail-fast'
|
1191
|
-
expect(last_response.status).to eq(400)
|
1192
|
-
expect(last_response.body).to eq('one is missing, two is missing, three is missing')
|
1193
|
-
end
|
1194
|
-
end
|
1195
|
-
|
1196
|
-
context 'when fail_fast is defined it stops the validation' do
|
1197
|
-
it 'of other params' do
|
1198
|
-
subject.params do
|
1199
|
-
requires :one, fail_fast: true
|
1200
|
-
requires :two
|
1201
|
-
end
|
1202
|
-
subject.get('/fail-fast') { declared(params).to_json }
|
1203
|
-
|
1204
|
-
get '/fail-fast'
|
1205
|
-
expect(last_response.status).to eq(400)
|
1206
|
-
expect(last_response.body).to eq('one is missing')
|
1207
|
-
end
|
1208
|
-
|
1209
|
-
it 'for a single param' do
|
1210
|
-
subject.params do
|
1211
|
-
requires :one, allow_blank: false, regexp: /[0-9]+/, fail_fast: true
|
1212
|
-
end
|
1213
|
-
subject.get('/fail-fast') { declared(params).to_json }
|
1214
|
-
|
1215
|
-
get '/fail-fast', one: ''
|
1216
|
-
expect(last_response.status).to eq(400)
|
1217
|
-
expect(last_response.body).to eq('one is empty')
|
1218
|
-
end
|
1219
|
-
end
|
1220
|
-
end
|
1221
|
-
|
1222
|
-
context 'when params have group attributes' do
|
1223
|
-
context 'with validations' do
|
1224
|
-
before do
|
1225
|
-
subject.params do
|
1226
|
-
with(allow_blank: false) do
|
1227
|
-
requires :id
|
1228
|
-
optional :name
|
1229
|
-
optional :address, allow_blank: true
|
1230
|
-
end
|
1231
|
-
end
|
1232
|
-
subject.get('test')
|
1233
|
-
end
|
1234
|
-
|
1235
|
-
context 'when data is invalid' do
|
1236
|
-
before do
|
1237
|
-
get 'test', id: '', name: ''
|
1238
|
-
end
|
1239
|
-
|
1240
|
-
it 'returns a validation error' do
|
1241
|
-
expect(last_response.status).to eq(400)
|
1242
|
-
end
|
1243
|
-
|
1244
|
-
it 'applies group validations for every parameter' do
|
1245
|
-
expect(last_response.body).to eq('id is empty, name is empty')
|
1246
|
-
end
|
1247
|
-
end
|
1248
|
-
|
1249
|
-
context 'when parameter has the same validator as a group' do
|
1250
|
-
before do
|
1251
|
-
get 'test', id: 'id', address: ''
|
1252
|
-
end
|
1253
|
-
|
1254
|
-
it 'returns a successful response' do
|
1255
|
-
expect(last_response.status).to eq(200)
|
1256
|
-
end
|
1257
|
-
|
1258
|
-
it 'prioritizes parameter validation over group validation' do
|
1259
|
-
expect(last_response.body).not_to include('address is empty')
|
1260
|
-
end
|
1261
|
-
end
|
1262
|
-
end
|
1263
|
-
|
1264
|
-
context 'with types' do
|
1265
|
-
before do
|
1266
|
-
subject.params do
|
1267
|
-
with(type: Date) do
|
1268
|
-
requires :created_at
|
1269
|
-
end
|
1270
|
-
end
|
1271
|
-
subject.get('test') { params[:created_at] }
|
1272
|
-
end
|
1273
|
-
|
1274
|
-
context 'when invalid date provided' do
|
1275
|
-
before do
|
1276
|
-
get 'test', created_at: 'not_a_date'
|
1277
|
-
end
|
1278
|
-
|
1279
|
-
it 'responds with HTTP error' do
|
1280
|
-
expect(last_response.status).to eq(400)
|
1281
|
-
end
|
1282
|
-
|
1283
|
-
it 'returns a validation error' do
|
1284
|
-
expect(last_response.body).to eq('created_at is invalid')
|
1285
|
-
end
|
1286
|
-
end
|
1287
|
-
|
1288
|
-
context 'when created_at receives a valid date' do
|
1289
|
-
before do
|
1290
|
-
get 'test', created_at: '2016-01-01'
|
1291
|
-
end
|
1292
|
-
|
1293
|
-
it 'returns a successful response' do
|
1294
|
-
expect(last_response.status).to eq(200)
|
1295
|
-
end
|
1296
|
-
|
1297
|
-
it 'returns a date' do
|
1298
|
-
expect(last_response.body).to eq('2016-01-01')
|
1299
|
-
end
|
1300
|
-
end
|
1301
|
-
end
|
1302
|
-
|
1303
|
-
context 'with several group attributes' do
|
1304
|
-
before do
|
1305
|
-
subject.params do
|
1306
|
-
with(values: [1]) do
|
1307
|
-
requires :id, type: Integer
|
1308
|
-
end
|
1309
|
-
|
1310
|
-
with(allow_blank: false) do
|
1311
|
-
optional :address, type: String
|
1312
|
-
end
|
1313
|
-
|
1314
|
-
requires :name
|
1315
|
-
end
|
1316
|
-
subject.get('test')
|
1317
|
-
end
|
1318
|
-
|
1319
|
-
context 'when data is invalid' do
|
1320
|
-
before do
|
1321
|
-
get 'test', id: 2, address: ''
|
1322
|
-
end
|
1323
|
-
|
1324
|
-
it 'responds with HTTP error' do
|
1325
|
-
expect(last_response.status).to eq(400)
|
1326
|
-
end
|
1327
|
-
|
1328
|
-
it 'returns a validation error' do
|
1329
|
-
expect(last_response.body).to eq('id does not have a valid value, address is empty, name is missing')
|
1330
|
-
end
|
1331
|
-
end
|
1332
|
-
|
1333
|
-
context 'when correct data is provided' do
|
1334
|
-
before do
|
1335
|
-
get 'test', id: 1, address: 'Some street', name: 'John'
|
1336
|
-
end
|
1337
|
-
|
1338
|
-
it 'returns a successful response' do
|
1339
|
-
expect(last_response.status).to eq(200)
|
1340
|
-
end
|
1341
|
-
end
|
1342
|
-
end
|
1343
|
-
|
1344
|
-
context 'with nested groups' do
|
1345
|
-
before do
|
1346
|
-
subject.params do
|
1347
|
-
with(type: Integer) do
|
1348
|
-
requires :id
|
1349
|
-
|
1350
|
-
with(type: Date) do
|
1351
|
-
requires :created_at
|
1352
|
-
optional :updated_at
|
1353
|
-
end
|
1354
|
-
end
|
1355
|
-
end
|
1356
|
-
subject.get('test')
|
1357
|
-
end
|
1358
|
-
|
1359
|
-
context 'when data is invalid' do
|
1360
|
-
before do
|
1361
|
-
get 'test', id: 'wrong', created_at: 'not_a_date', updated_at: '2016-01-01'
|
1362
|
-
end
|
1363
|
-
|
1364
|
-
it 'responds with HTTP error' do
|
1365
|
-
expect(last_response.status).to eq(400)
|
1366
|
-
end
|
1367
|
-
|
1368
|
-
it 'returns a validation error' do
|
1369
|
-
expect(last_response.body).to eq('id is invalid, created_at is invalid')
|
1370
|
-
end
|
1371
|
-
end
|
1372
|
-
|
1373
|
-
context 'when correct data is provided' do
|
1374
|
-
before do
|
1375
|
-
get 'test', id: 1, created_at: '2016-01-01'
|
1376
|
-
end
|
1377
|
-
|
1378
|
-
it 'returns a successful response' do
|
1379
|
-
expect(last_response.status).to eq(200)
|
1380
|
-
end
|
1381
|
-
end
|
1382
|
-
end
|
1383
|
-
end
|
1384
|
-
|
1385
|
-
context 'with exactly_one_of validation for optional parameters within an Hash param' do
|
1386
|
-
before do
|
1387
|
-
subject.params do
|
1388
|
-
optional :memo, type: Hash do
|
1389
|
-
optional :text, type: String
|
1390
|
-
optional :custom_body, type: Hash, coerce_with: JSON
|
1391
|
-
exactly_one_of :text, :custom_body
|
1392
|
-
end
|
1393
|
-
end
|
1394
|
-
subject.get('test')
|
1395
|
-
end
|
1396
|
-
|
1397
|
-
context 'when correct data is provided' do
|
1398
|
-
it 'returns a successful response' do
|
1399
|
-
get 'test', memo: {}
|
1400
|
-
expect(last_response.status).to eq(200)
|
1401
|
-
|
1402
|
-
get 'test', memo: { text: 'HOGEHOGE' }
|
1403
|
-
expect(last_response.status).to eq(200)
|
1404
|
-
|
1405
|
-
get 'test', memo: { custom_body: '{ "xxx": "yyy" }' }
|
1406
|
-
expect(last_response.status).to eq(200)
|
1407
|
-
end
|
1408
|
-
end
|
1409
|
-
|
1410
|
-
context 'when invalid data is provided' do
|
1411
|
-
it 'returns a failure response' do
|
1412
|
-
get 'test', memo: { text: 'HOGEHOGE', custom_body: '{ "xxx": "yyy" }' }
|
1413
|
-
expect(last_response.status).to eq(400)
|
1414
|
-
|
1415
|
-
get 'test', memo: '{ "custom_body": "HOGE" }'
|
1416
|
-
expect(last_response.status).to eq(400)
|
1417
|
-
end
|
1418
|
-
end
|
1419
|
-
end
|
1420
|
-
end
|