Skip to content

Commit 0ca9feb

Browse files
committed
specify type in group of required params (#722)
1 parent 3eea554 commit 0ca9feb

File tree

7 files changed

+87
-14
lines changed

7 files changed

+87
-14
lines changed

lib/grape.rb

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ module Exceptions
5555
autoload :UnknownOptions, 'grape/exceptions/unknown_options'
5656
autoload :InvalidWithOptionForRepresent, 'grape/exceptions/invalid_with_option_for_represent'
5757
autoload :IncompatibleOptionValues, 'grape/exceptions/incompatible_option_values'
58+
autoload :InvalidGroupType, 'grape/exceptions/invalid_group_type'
5859
end
5960

6061
module ErrorFormatter
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# encoding: utf-8
2+
module Grape
3+
module Exceptions
4+
class InvalidGroupType < Base
5+
def initialize(group_type)
6+
super(message: compose_message('invalid_group_type', group_type: group_type))
7+
end
8+
end
9+
end
10+
end

lib/grape/locale/en.yml

+1
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ en:
3333
at_least_one: 'are missing, at least one parameter must be provided'
3434
exactly_one: 'are missing, exactly one parameter must be provided'
3535
all_or_none: 'provide all or none of parameters'
36+
invalid_group_type: 'group of required parameters must have a specified type of Array or Hash, type provided: %{group_type}'
3637

lib/grape/validations/params_scope.rb

+6
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ def validate_attributes(attrs, opts, &block)
7272
end
7373

7474
def new_scope(attrs, optional = false, &block)
75+
# if required params are grouped and no type or unsupported type is provided, raise an error
76+
type = attrs[1] ? attrs[1][:type] : nil
77+
if attrs.first && (type.nil? || (type != Array && type != Hash))
78+
fail Grape::Exceptions::InvalidGroupType.new(type) unless optional
79+
end
80+
7581
opts = attrs[1] || { type: Array }
7682
ParamsScope.new(api: @api, element: attrs.first, parent: self, optional: optional, type: opts[:type], &block)
7783
end

spec/grape/api_spec.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -2166,11 +2166,11 @@ def static
21662166
it 'groups nested params and prevents overwriting of params with same name in different groups' do
21672167
subject.desc 'method'
21682168
subject.params do
2169-
group :group1 do
2169+
group :group1, type: Array do
21702170
optional :param1, desc: 'group1 param1 desc'
21712171
requires :param2, desc: 'group1 param2 desc'
21722172
end
2173-
group :group2 do
2173+
group :group2, type: Array do
21742174
optional :param1, desc: 'group2 param1 desc'
21752175
requires :param2, desc: 'group2 param2 desc'
21762176
end
@@ -2190,7 +2190,7 @@ def static
21902190
subject.desc 'nesting'
21912191
subject.params do
21922192
requires :root_param, desc: 'root param'
2193-
group :nested do
2193+
group :nested, type: Array do
21942194
requires :nested_param, desc: 'nested param'
21952195
end
21962196
end

spec/grape/validations/params_scope_spec.rb

+55
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,59 @@ def app
5454
end.to raise_error Grape::Exceptions::IncompatibleOptionValues
5555
end
5656
end
57+
58+
context 'parameters in group' do
59+
it 'errors when no type is provided' do
60+
expect do
61+
subject.params do
62+
group :a do
63+
requires :b
64+
end
65+
end
66+
end.to raise_error Grape::Exceptions::InvalidGroupType
67+
end
68+
69+
it 'allows Hash as type' do
70+
subject.params do
71+
group :a, type: Hash do
72+
requires :b
73+
end
74+
end
75+
subject.get('/group') { 'group works' }
76+
get '/group', a: { b: true }
77+
expect(last_response.status).to eq(200)
78+
expect(last_response.body).to eq('group works')
79+
end
80+
81+
it 'allows Array as type' do
82+
subject.params do
83+
group :a, type: Array do
84+
requires :b
85+
end
86+
end
87+
subject.get('/group') { 'group works' }
88+
get '/group', a: [{ b: true }]
89+
expect(last_response.status).to eq(200)
90+
expect(last_response.body).to eq('group works')
91+
end
92+
93+
it 'errors with an unsupported type' do
94+
expect do
95+
subject.params do
96+
group :a, type: Set do
97+
requires :b
98+
end
99+
end
100+
end.to raise_error Grape::Exceptions::InvalidGroupType
101+
end
102+
103+
it 'works with optional parameters' do
104+
subject.params do
105+
optional :user, type: Hash do
106+
requires :name, allow_blank: false
107+
end
108+
end
109+
get '/group'
110+
end
111+
end
57112
end

spec/grape/validations_spec.rb

+11-11
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def define_requires_none
228228

229229
it 'adds to declared parameters' do
230230
subject.params do
231-
requires :items do
231+
requires :items, type: Array do
232232
requires :key
233233
end
234234
end
@@ -272,7 +272,7 @@ def define_requires_none
272272

273273
it 'adds to declared parameters' do
274274
subject.params do
275-
requires :items do
275+
requires :items, type: Array do
276276
requires :key
277277
end
278278
end
@@ -283,7 +283,7 @@ def define_requires_none
283283
context 'group' do
284284
before do
285285
subject.params do
286-
group :items do
286+
group :items, type: Array do
287287
requires :key
288288
end
289289
end
@@ -306,7 +306,7 @@ def define_requires_none
306306

307307
it 'adds to declared parameters' do
308308
subject.params do
309-
group :items do
309+
group :items, type: Array do
310310
requires :key
311311
end
312312
end
@@ -395,9 +395,9 @@ def validate_param!(attr_name, params)
395395
context 'validation within arrays' do
396396
before do
397397
subject.params do
398-
group :children do
398+
group :children, type: Array do
399399
requires :name
400-
group :parents do
400+
group :parents, type: Array do
401401
requires :name
402402
end
403403
end
@@ -457,7 +457,7 @@ def validate_param!(attr_name, params)
457457
context 'with block param' do
458458
before do
459459
subject.params do
460-
requires :planets do
460+
requires :planets, type: Array do
461461
requires :name
462462
end
463463
end
@@ -469,7 +469,7 @@ def validate_param!(attr_name, params)
469469
end
470470

471471
subject.params do
472-
group :stars do
472+
group :stars, type: Array do
473473
requires :name
474474
end
475475
end
@@ -549,9 +549,9 @@ def validate_param!(attr_name, params)
549549
context 'validation within arrays with JSON' do
550550
before do
551551
subject.params do
552-
group :children do
552+
group :children, type: Array do
553553
requires :name
554-
group :parents do
554+
group :parents, type: Array do
555555
requires :name
556556
end
557557
end
@@ -695,7 +695,7 @@ def validate_param!(attr_name, params)
695695
optional :items do
696696
requires :key
697697
optional(:optional_subitems) { requires :value }
698-
requires(:required_subitems) { requires :value }
698+
requires(:required_subitems, type: Array) { requires :value }
699699
end
700700
end
701701
expect(subject.route_setting(:declared_params)).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]])

0 commit comments

Comments
 (0)