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.

Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -1
  4. data/CHANGELOG.md +18 -0
  5. data/Gemfile +1 -1
  6. data/README.md +124 -9
  7. data/UPGRADING.md +66 -0
  8. data/gemfiles/rails_3.gemfile +1 -1
  9. data/gemfiles/rails_4.gemfile +1 -1
  10. data/lib/grape.rb +4 -0
  11. data/lib/grape/api.rb +1 -5
  12. data/lib/grape/dsl/inside_route.rb +2 -1
  13. data/lib/grape/dsl/parameters.rb +20 -9
  14. data/lib/grape/dsl/routing.rb +11 -1
  15. data/lib/grape/error_formatter/base.rb +1 -1
  16. data/lib/grape/exceptions/invalid_accept_header.rb +10 -0
  17. data/lib/grape/exceptions/invalid_message_body.rb +10 -0
  18. data/lib/grape/exceptions/missing_group_type.rb +10 -0
  19. data/lib/grape/exceptions/unsupported_group_type.rb +10 -0
  20. data/lib/grape/http/request.rb +1 -0
  21. data/lib/grape/locale/en.yml +11 -0
  22. data/lib/grape/middleware/base.rb +1 -1
  23. data/lib/grape/middleware/formatter.rb +2 -0
  24. data/lib/grape/middleware/versioner/header.rb +14 -11
  25. data/lib/grape/parser/json.rb +3 -0
  26. data/lib/grape/parser/xml.rb +3 -0
  27. data/lib/grape/validations/params_scope.rb +20 -4
  28. data/lib/grape/validations/validators/coerce.rb +4 -1
  29. data/lib/grape/validations/validators/values.rb +1 -1
  30. data/lib/grape/version.rb +1 -1
  31. data/spec/grape/api_spec.rb +3 -3
  32. data/spec/grape/dsl/parameters_spec.rb +11 -11
  33. data/spec/grape/dsl/routing_spec.rb +13 -4
  34. data/spec/grape/endpoint_spec.rb +2 -2
  35. data/spec/grape/exceptions/body_parse_errors_spec.rb +105 -0
  36. data/spec/grape/exceptions/invalid_accept_header_spec.rb +330 -0
  37. data/spec/grape/integration/rack_spec.rb +32 -0
  38. data/spec/grape/middleware/base_spec.rb +20 -0
  39. data/spec/grape/middleware/versioner/header_spec.rb +74 -96
  40. data/spec/grape/validations/params_scope_spec.rb +124 -0
  41. data/spec/grape/validations/validators/allow_blank_spec.rb +102 -0
  42. data/spec/grape/validations/validators/values_spec.rb +45 -1
  43. data/spec/grape/validations_spec.rb +54 -16
  44. data/spec/shared/versioning_examples.rb +32 -0
  45. 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] }]])