grape 0.10.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grape might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +1 -1
- data/CHANGELOG.md +18 -0
- data/Gemfile +1 -1
- data/README.md +124 -9
- data/UPGRADING.md +66 -0
- data/gemfiles/rails_3.gemfile +1 -1
- data/gemfiles/rails_4.gemfile +1 -1
- data/lib/grape.rb +4 -0
- data/lib/grape/api.rb +1 -5
- data/lib/grape/dsl/inside_route.rb +2 -1
- data/lib/grape/dsl/parameters.rb +20 -9
- data/lib/grape/dsl/routing.rb +11 -1
- data/lib/grape/error_formatter/base.rb +1 -1
- data/lib/grape/exceptions/invalid_accept_header.rb +10 -0
- data/lib/grape/exceptions/invalid_message_body.rb +10 -0
- data/lib/grape/exceptions/missing_group_type.rb +10 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +10 -0
- data/lib/grape/http/request.rb +1 -0
- data/lib/grape/locale/en.yml +11 -0
- data/lib/grape/middleware/base.rb +1 -1
- data/lib/grape/middleware/formatter.rb +2 -0
- data/lib/grape/middleware/versioner/header.rb +14 -11
- data/lib/grape/parser/json.rb +3 -0
- data/lib/grape/parser/xml.rb +3 -0
- data/lib/grape/validations/params_scope.rb +20 -4
- data/lib/grape/validations/validators/coerce.rb +4 -1
- data/lib/grape/validations/validators/values.rb +1 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +3 -3
- data/spec/grape/dsl/parameters_spec.rb +11 -11
- data/spec/grape/dsl/routing_spec.rb +13 -4
- data/spec/grape/endpoint_spec.rb +2 -2
- data/spec/grape/exceptions/body_parse_errors_spec.rb +105 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +330 -0
- data/spec/grape/integration/rack_spec.rb +32 -0
- data/spec/grape/middleware/base_spec.rb +20 -0
- data/spec/grape/middleware/versioner/header_spec.rb +74 -96
- data/spec/grape/validations/params_scope_spec.rb +124 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +102 -0
- data/spec/grape/validations/validators/values_spec.rb +45 -1
- data/spec/grape/validations_spec.rb +54 -16
- data/spec/shared/versioning_examples.rb +32 -0
- metadata +61 -51
@@ -53,5 +53,129 @@ describe Grape::Validations::ParamsScope do
|
|
53
53
|
subject.params { requires :numbers, type: Array, values: [1, 'definitely not a number', 3] }
|
54
54
|
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
55
55
|
end
|
56
|
+
|
57
|
+
it 'raises exception when range values have different endpoint types' do
|
58
|
+
expect do
|
59
|
+
subject.params { requires :numbers, type: Array, values: 0.0..10 }
|
60
|
+
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'with range values' do
|
65
|
+
context "when left range endpoint isn't #kind_of? the type" do
|
66
|
+
it 'raises exception' do
|
67
|
+
expect do
|
68
|
+
subject.params { requires :latitude, type: Integer, values: -90.0..90 }
|
69
|
+
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when right range endpoint isn't #kind_of? the type" do
|
74
|
+
it 'raises exception' do
|
75
|
+
expect do
|
76
|
+
subject.params { requires :latitude, type: Integer, values: -90..90.0 }
|
77
|
+
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when both range endpoints are #kind_of? the type' do
|
82
|
+
it 'accepts values in the range' do
|
83
|
+
subject.params do
|
84
|
+
requires :letter, type: String, values: 'a'..'z'
|
85
|
+
end
|
86
|
+
subject.get('/letter') { params[:letter] }
|
87
|
+
|
88
|
+
get '/letter', letter: 'j'
|
89
|
+
expect(last_response.status).to eq(200)
|
90
|
+
expect(last_response.body).to eq('j')
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'rejects values outside the range' do
|
94
|
+
subject.params do
|
95
|
+
requires :letter, type: String, values: 'a'..'z'
|
96
|
+
end
|
97
|
+
subject.get('/letter') { params[:letter] }
|
98
|
+
|
99
|
+
get '/letter', letter: 'J'
|
100
|
+
expect(last_response.status).to eq(400)
|
101
|
+
expect(last_response.body).to eq('letter does not have a valid value')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'parameters in group' do
|
107
|
+
it 'errors when no type is provided' do
|
108
|
+
expect do
|
109
|
+
subject.params do
|
110
|
+
group :a do
|
111
|
+
requires :b
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end.to raise_error Grape::Exceptions::MissingGroupTypeError
|
115
|
+
|
116
|
+
expect do
|
117
|
+
subject.params do
|
118
|
+
optional :a do
|
119
|
+
requires :b
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end.to raise_error Grape::Exceptions::MissingGroupTypeError
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'allows Hash as type' do
|
126
|
+
subject.params do
|
127
|
+
group :a, type: Hash do
|
128
|
+
requires :b
|
129
|
+
end
|
130
|
+
end
|
131
|
+
subject.get('/group') { 'group works' }
|
132
|
+
get '/group', a: { b: true }
|
133
|
+
expect(last_response.status).to eq(200)
|
134
|
+
expect(last_response.body).to eq('group works')
|
135
|
+
|
136
|
+
subject.params do
|
137
|
+
optional :a, type: Hash do
|
138
|
+
requires :b
|
139
|
+
end
|
140
|
+
end
|
141
|
+
get '/optional_type_hash'
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'allows Array as type' do
|
145
|
+
subject.params do
|
146
|
+
group :a, type: Array do
|
147
|
+
requires :b
|
148
|
+
end
|
149
|
+
end
|
150
|
+
subject.get('/group') { 'group works' }
|
151
|
+
get '/group', a: [{ b: true }]
|
152
|
+
expect(last_response.status).to eq(200)
|
153
|
+
expect(last_response.body).to eq('group works')
|
154
|
+
|
155
|
+
subject.params do
|
156
|
+
optional :a, type: Array do
|
157
|
+
requires :b
|
158
|
+
end
|
159
|
+
end
|
160
|
+
get '/optional_type_array'
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'errors with an unsupported type' do
|
164
|
+
expect do
|
165
|
+
subject.params do
|
166
|
+
group :a, type: Set do
|
167
|
+
requires :b
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end.to raise_error Grape::Exceptions::UnsupportedGroupTypeError
|
171
|
+
|
172
|
+
expect do
|
173
|
+
subject.params do
|
174
|
+
optional :a, type: Set do
|
175
|
+
requires :b
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end.to raise_error Grape::Exceptions::UnsupportedGroupTypeError
|
179
|
+
end
|
56
180
|
end
|
57
181
|
end
|
@@ -21,6 +21,51 @@ describe Grape::Validations::AllowBlankValidator do
|
|
21
21
|
end
|
22
22
|
get '/allow_blank'
|
23
23
|
|
24
|
+
params do
|
25
|
+
requires :val, type: DateTime, allow_blank: true
|
26
|
+
end
|
27
|
+
get '/allow_datetime_blank'
|
28
|
+
|
29
|
+
params do
|
30
|
+
requires :val, type: DateTime, allow_blank: false
|
31
|
+
end
|
32
|
+
get '/disallow_datetime_blank'
|
33
|
+
|
34
|
+
params do
|
35
|
+
requires :val, type: DateTime
|
36
|
+
end
|
37
|
+
get '/default_allow_datetime_blank'
|
38
|
+
|
39
|
+
params do
|
40
|
+
requires :val, type: Date, allow_blank: true
|
41
|
+
end
|
42
|
+
get '/allow_date_blank'
|
43
|
+
|
44
|
+
params do
|
45
|
+
requires :val, type: Integer, allow_blank: true
|
46
|
+
end
|
47
|
+
get '/allow_integer_blank'
|
48
|
+
|
49
|
+
params do
|
50
|
+
requires :val, type: Float, allow_blank: true
|
51
|
+
end
|
52
|
+
get '/allow_float_blank'
|
53
|
+
|
54
|
+
params do
|
55
|
+
requires :val, type: Fixnum, allow_blank: true
|
56
|
+
end
|
57
|
+
get '/allow_fixnum_blank'
|
58
|
+
|
59
|
+
params do
|
60
|
+
requires :val, type: Symbol, allow_blank: true
|
61
|
+
end
|
62
|
+
get '/allow_symbol_blank'
|
63
|
+
|
64
|
+
params do
|
65
|
+
requires :val, type: Boolean, allow_blank: true
|
66
|
+
end
|
67
|
+
get '/allow_boolean_blank'
|
68
|
+
|
24
69
|
params do
|
25
70
|
optional :user, type: Hash do
|
26
71
|
requires :name, allow_blank: false
|
@@ -28,6 +73,13 @@ describe Grape::Validations::AllowBlankValidator do
|
|
28
73
|
end
|
29
74
|
get '/disallow_blank_required_param_in_an_optional_group'
|
30
75
|
|
76
|
+
params do
|
77
|
+
optional :user, type: Hash do
|
78
|
+
requires :name, type: Date, allow_blank: true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
get '/allow_blank_date_param_in_an_optional_group'
|
82
|
+
|
31
83
|
params do
|
32
84
|
optional :user, type: Hash do
|
33
85
|
optional :name, allow_blank: false
|
@@ -75,6 +127,9 @@ describe Grape::Validations::AllowBlankValidator do
|
|
75
127
|
it 'refuses empty string' do
|
76
128
|
get '/', name: ''
|
77
129
|
expect(last_response.status).to eq(400)
|
130
|
+
|
131
|
+
get '/disallow_datetime_blank', val: ''
|
132
|
+
expect(last_response.status).to eq(400)
|
78
133
|
end
|
79
134
|
|
80
135
|
it 'refuses only whitespaces' do
|
@@ -104,6 +159,48 @@ describe Grape::Validations::AllowBlankValidator do
|
|
104
159
|
get '/allow_blank', name: ''
|
105
160
|
expect(last_response.status).to eq(200)
|
106
161
|
end
|
162
|
+
|
163
|
+
it 'accepts empty input' do
|
164
|
+
get '/default_allow_datetime_blank', val: ''
|
165
|
+
expect(last_response.status).to eq(200)
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'accepts empty when datetime allow_blank' do
|
169
|
+
get '/allow_datetime_blank', val: ''
|
170
|
+
expect(last_response.status).to eq(200)
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'accepts empty when date allow_blank' do
|
174
|
+
get '/allow_date_blank', val: ''
|
175
|
+
expect(last_response.status).to eq(200)
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'allow_blank when Numeric' do
|
179
|
+
it 'accepts empty when integer allow_blank' do
|
180
|
+
get '/allow_integer_blank', val: ''
|
181
|
+
expect(last_response.status).to eq(200)
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'accepts empty when float allow_blank' do
|
185
|
+
get '/allow_float_blank', val: ''
|
186
|
+
expect(last_response.status).to eq(200)
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'accepts empty when fixnum allow_blank' do
|
190
|
+
get '/allow_fixnum_blank', val: ''
|
191
|
+
expect(last_response.status).to eq(200)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'accepts empty when symbol allow_blank' do
|
196
|
+
get '/allow_symbol_blank', val: ''
|
197
|
+
expect(last_response.status).to eq(200)
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'accepts empty when boolean allow_blank' do
|
201
|
+
get '/allow_boolean_blank', val: ''
|
202
|
+
expect(last_response.status).to eq(200)
|
203
|
+
end
|
107
204
|
end
|
108
205
|
|
109
206
|
context 'in an optional group' do
|
@@ -113,6 +210,11 @@ describe Grape::Validations::AllowBlankValidator do
|
|
113
210
|
expect(last_response.status).to eq(200)
|
114
211
|
end
|
115
212
|
|
213
|
+
it 'accepts a nested missing date value' do
|
214
|
+
get '/allow_blank_date_param_in_an_optional_group', user: { name: '' }
|
215
|
+
expect(last_response.status).to eq(200)
|
216
|
+
end
|
217
|
+
|
116
218
|
it 'refuses a blank value in an existing group' do
|
117
219
|
get '/disallow_blank_required_param_in_an_optional_group', user: { name: '' }
|
118
220
|
expect(last_response.status).to eq(400)
|
@@ -71,7 +71,7 @@ describe Grape::Validations::ValuesValidator do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
params do
|
74
|
-
optional :optional do
|
74
|
+
optional :optional, type: Array do
|
75
75
|
requires :type, values: %w(a b)
|
76
76
|
end
|
77
77
|
end
|
@@ -221,4 +221,48 @@ describe Grape::Validations::ValuesValidator do
|
|
221
221
|
expect(last_response.status).to eq 200
|
222
222
|
end
|
223
223
|
end
|
224
|
+
|
225
|
+
context 'with a range of values' do
|
226
|
+
subject(:app) do
|
227
|
+
Class.new(Grape::API) do
|
228
|
+
params do
|
229
|
+
optional :value, type: Float, values: 0.0..10.0
|
230
|
+
end
|
231
|
+
get '/value' do
|
232
|
+
{ value: params[:value] }.to_json
|
233
|
+
end
|
234
|
+
|
235
|
+
params do
|
236
|
+
optional :values, type: Array[Float], values: 0.0..10.0
|
237
|
+
end
|
238
|
+
get '/values' do
|
239
|
+
{ values: params[:values] }.to_json
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'allows a single value inside of the range' do
|
245
|
+
get('/value', value: 5.2)
|
246
|
+
expect(last_response.status).to eq 200
|
247
|
+
expect(last_response.body).to eq({ value: 5.2 }.to_json)
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'allows an array of values inside of the range' do
|
251
|
+
get('/values', values: [8.6, 7.5, 3, 0.9])
|
252
|
+
expect(last_response.status).to eq 200
|
253
|
+
expect(last_response.body).to eq({ values: [8.6, 7.5, 3.0, 0.9] }.to_json)
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'rejects a single value outside the range' do
|
257
|
+
get('/value', value: 'a')
|
258
|
+
expect(last_response.status).to eq 400
|
259
|
+
expect(last_response.body).to eq('value is invalid, value does not have a valid value')
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'rejects an array of values if any of them are outside the range' do
|
263
|
+
get('/values', values: [8.6, 75, 3, 0.9])
|
264
|
+
expect(last_response.status).to eq 400
|
265
|
+
expect(last_response.body).to eq('values does not have a valid value')
|
266
|
+
end
|
267
|
+
end
|
224
268
|
end
|
@@ -47,6 +47,44 @@ describe Grape::Validations do
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
context 'optional using Grape::Entity documentation' do
|
51
|
+
def define_optional_using
|
52
|
+
documentation = { field_a: { type: String }, field_b: { type: String } }
|
53
|
+
subject.params do
|
54
|
+
optional :all, using: documentation
|
55
|
+
end
|
56
|
+
end
|
57
|
+
before do
|
58
|
+
define_optional_using
|
59
|
+
subject.get '/optional' do
|
60
|
+
'optional with using works'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'adds entity documentation to declared params' do
|
65
|
+
define_optional_using
|
66
|
+
expect(subject.route_setting(:declared_params)).to eq([:field_a, :field_b])
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'works when field_a and field_b are not present' do
|
70
|
+
get '/optional'
|
71
|
+
expect(last_response.status).to eq(200)
|
72
|
+
expect(last_response.body).to eq('optional with using works')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'works when field_a is present' do
|
76
|
+
get '/optional', field_a: 'woof'
|
77
|
+
expect(last_response.status).to eq(200)
|
78
|
+
expect(last_response.body).to eq('optional with using works')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'works when field_b is present' do
|
82
|
+
get '/optional', field_b: 'woof'
|
83
|
+
expect(last_response.status).to eq(200)
|
84
|
+
expect(last_response.body).to eq('optional with using works')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
50
88
|
context 'required' do
|
51
89
|
before do
|
52
90
|
subject.params do
|
@@ -228,7 +266,7 @@ describe Grape::Validations do
|
|
228
266
|
|
229
267
|
it 'adds to declared parameters' do
|
230
268
|
subject.params do
|
231
|
-
requires :items do
|
269
|
+
requires :items, type: Array do
|
232
270
|
requires :key
|
233
271
|
end
|
234
272
|
end
|
@@ -272,7 +310,7 @@ describe Grape::Validations do
|
|
272
310
|
|
273
311
|
it 'adds to declared parameters' do
|
274
312
|
subject.params do
|
275
|
-
requires :items do
|
313
|
+
requires :items, type: Array do
|
276
314
|
requires :key
|
277
315
|
end
|
278
316
|
end
|
@@ -283,7 +321,7 @@ describe Grape::Validations do
|
|
283
321
|
context 'group' do
|
284
322
|
before do
|
285
323
|
subject.params do
|
286
|
-
group :items do
|
324
|
+
group :items, type: Array do
|
287
325
|
requires :key
|
288
326
|
end
|
289
327
|
end
|
@@ -306,7 +344,7 @@ describe Grape::Validations do
|
|
306
344
|
|
307
345
|
it 'adds to declared parameters' do
|
308
346
|
subject.params do
|
309
|
-
group :items do
|
347
|
+
group :items, type: Array do
|
310
348
|
requires :key
|
311
349
|
end
|
312
350
|
end
|
@@ -319,7 +357,7 @@ describe Grape::Validations do
|
|
319
357
|
|
320
358
|
before do
|
321
359
|
subject.params do
|
322
|
-
optional :items do
|
360
|
+
optional :items, type: Array do
|
323
361
|
optional :key1, type: String
|
324
362
|
optional :key2, type: String
|
325
363
|
end
|
@@ -395,9 +433,9 @@ describe Grape::Validations do
|
|
395
433
|
context 'validation within arrays' do
|
396
434
|
before do
|
397
435
|
subject.params do
|
398
|
-
group :children do
|
436
|
+
group :children, type: Array do
|
399
437
|
requires :name
|
400
|
-
group :parents do
|
438
|
+
group :parents, type: Array do
|
401
439
|
requires :name
|
402
440
|
end
|
403
441
|
end
|
@@ -457,7 +495,7 @@ describe Grape::Validations do
|
|
457
495
|
context 'with block param' do
|
458
496
|
before do
|
459
497
|
subject.params do
|
460
|
-
requires :planets do
|
498
|
+
requires :planets, type: Array do
|
461
499
|
requires :name
|
462
500
|
end
|
463
501
|
end
|
@@ -469,7 +507,7 @@ describe Grape::Validations do
|
|
469
507
|
end
|
470
508
|
|
471
509
|
subject.params do
|
472
|
-
group :stars do
|
510
|
+
group :stars, type: Array do
|
473
511
|
requires :name
|
474
512
|
end
|
475
513
|
end
|
@@ -482,7 +520,7 @@ describe Grape::Validations do
|
|
482
520
|
|
483
521
|
subject.params do
|
484
522
|
requires :name
|
485
|
-
optional :moons do
|
523
|
+
optional :moons, type: Array do
|
486
524
|
requires :name
|
487
525
|
end
|
488
526
|
end
|
@@ -549,9 +587,9 @@ describe Grape::Validations do
|
|
549
587
|
context 'validation within arrays with JSON' do
|
550
588
|
before do
|
551
589
|
subject.params do
|
552
|
-
group :children do
|
590
|
+
group :children, type: Array do
|
553
591
|
requires :name
|
554
|
-
group :parents do
|
592
|
+
group :parents, type: Array do
|
555
593
|
requires :name
|
556
594
|
end
|
557
595
|
end
|
@@ -630,7 +668,7 @@ describe Grape::Validations do
|
|
630
668
|
|
631
669
|
it 'adds to declared parameters' do
|
632
670
|
subject.params do
|
633
|
-
optional :items do
|
671
|
+
optional :items, type: Array do
|
634
672
|
requires :key
|
635
673
|
end
|
636
674
|
end
|
@@ -692,10 +730,10 @@ describe Grape::Validations do
|
|
692
730
|
|
693
731
|
it 'adds to declared parameters' do
|
694
732
|
subject.params do
|
695
|
-
optional :items do
|
733
|
+
optional :items, type: Array do
|
696
734
|
requires :key
|
697
|
-
optional(:optional_subitems) { requires :value }
|
698
|
-
requires(:required_subitems) { requires :value }
|
735
|
+
optional(:optional_subitems, type: Array) { requires :value }
|
736
|
+
requires(:required_subitems, type: Array) { requires :value }
|
699
737
|
end
|
700
738
|
end
|
701
739
|
expect(subject.route_setting(:declared_params)).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]])
|