Skip to content

Commit

Permalink
Make type of groupped parameters required (#722)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrichter1 committed Jan 26, 2015
1 parent f3fe0eb commit 0bf6fb2
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Next Release
* [#879](https://github.com/intridea/grape/pull/879): The `route_info` value is no longer included in `params` Hash - [@rodzyn](https://github.com/rodzyn).
* [#881](https://github.com/intridea/grape/issues/881): Fixed `Grape::Validations::ValuesValidator` support for `Range` type - [@ajvondrak](https://github.com/ajvondrak).
* [#901](https://github.com/intridea/grape/pull/901): Fix: callbacks defined in a version block are only called for the routes defined in that block - [@kushkella](https://github.com/kushkella).
* [#886](https://github.com/intridea/grape/pull/886): Group of parameters made to require an explicit type of Hash or Array - [@jrichter1](https://github.com/jrichter1).
* Your contribution here.

0.10.1 (12/28/2014)
Expand Down
2 changes: 2 additions & 0 deletions lib/grape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ module Exceptions
autoload :UnknownOptions, 'grape/exceptions/unknown_options'
autoload :InvalidWithOptionForRepresent, 'grape/exceptions/invalid_with_option_for_represent'
autoload :IncompatibleOptionValues, 'grape/exceptions/incompatible_option_values'
autoload :MissingGroupTypeError, 'grape/exceptions/missing_group_type'
autoload :UnsupportedGroupTypeError, 'grape/exceptions/unsupported_group_type'
end

module ErrorFormatter
Expand Down
7 changes: 7 additions & 0 deletions lib/grape/dsl/parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ def optional(*attrs, &block)
orig_attrs = attrs.clone

opts = attrs.last.is_a?(Hash) ? attrs.pop : {}
type = opts[:type]

# check type for optional parameter group
if attrs && block_given?
fail Grape::Exceptions::MissingGroupTypeError.new if type.nil?
fail Grape::Exceptions::UnsupportedGroupTypeError.new unless [Array, Hash].include?(type)
end

validate_attributes(attrs, opts, &block)

Expand Down
10 changes: 10 additions & 0 deletions lib/grape/exceptions/missing_group_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# encoding: utf-8
module Grape
module Exceptions
class MissingGroupTypeError < Base
def initialize
super(message: compose_message('missing_group_type'))
end
end
end
end
10 changes: 10 additions & 0 deletions lib/grape/exceptions/unsupported_group_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# encoding: utf-8
module Grape
module Exceptions
class UnsupportedGroupTypeError < Base
def initialize
super(message: compose_message('unsupported_group_type'))
end
end
end
end
2 changes: 2 additions & 0 deletions lib/grape/locale/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ en:
at_least_one: 'are missing, at least one parameter must be provided'
exactly_one: 'are missing, exactly one parameter must be provided'
all_or_none: 'provide all or none of parameters'
missing_group_type: 'group type is required'
unsupported_group_type: 'group type must be Array or Hash'

7 changes: 7 additions & 0 deletions lib/grape/validations/params_scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ def validate_attributes(attrs, opts, &block)
end

def new_scope(attrs, optional = false, &block)
# if required params are grouped and no type or unsupported type is provided, raise an error
type = attrs[1] ? attrs[1][:type] : nil
if attrs.first && !optional
fail Grape::Exceptions::MissingGroupTypeError.new if type.nil?
fail Grape::Exceptions::UnsupportedGroupTypeError.new unless [Array, Hash].include?(type)
end

opts = attrs[1] || { type: Array }
ParamsScope.new(api: @api, element: attrs.first, parent: self, optional: optional, type: opts[:type], &block)
end
Expand Down
6 changes: 3 additions & 3 deletions spec/grape/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2166,11 +2166,11 @@ def static
it 'groups nested params and prevents overwriting of params with same name in different groups' do
subject.desc 'method'
subject.params do
group :group1 do
group :group1, type: Array do
optional :param1, desc: 'group1 param1 desc'
requires :param2, desc: 'group1 param2 desc'
end
group :group2 do
group :group2, type: Array do
optional :param1, desc: 'group2 param1 desc'
requires :param2, desc: 'group2 param2 desc'
end
Expand All @@ -2190,7 +2190,7 @@ def static
subject.desc 'nesting'
subject.params do
requires :root_param, desc: 'root param'
group :nested do
group :nested, type: Array do
requires :nested_param, desc: 'nested param'
end
end
Expand Down
76 changes: 76 additions & 0 deletions spec/grape/validations/params_scope_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,80 @@ def app
end
end
end

context 'parameters in group' do
it 'errors when no type is provided' do
expect do
subject.params do
group :a do
requires :b
end
end
end.to raise_error Grape::Exceptions::MissingGroupTypeError

expect do
subject.params do
optional :a do
requires :b
end
end
end.to raise_error Grape::Exceptions::MissingGroupTypeError
end

it 'allows Hash as type' do
subject.params do
group :a, type: Hash do
requires :b
end
end
subject.get('/group') { 'group works' }
get '/group', a: { b: true }
expect(last_response.status).to eq(200)
expect(last_response.body).to eq('group works')

subject.params do
optional :a, type: Hash do
requires :b
end
end
get '/optional_type_hash'
end

it 'allows Array as type' do
subject.params do
group :a, type: Array do
requires :b
end
end
subject.get('/group') { 'group works' }
get '/group', a: [{ b: true }]
expect(last_response.status).to eq(200)
expect(last_response.body).to eq('group works')

subject.params do
optional :a, type: Array do
requires :b
end
end
get '/optional_type_array'
end

it 'errors with an unsupported type' do
expect do
subject.params do
group :a, type: Set do
requires :b
end
end
end.to raise_error Grape::Exceptions::UnsupportedGroupTypeError

expect do
subject.params do
optional :a, type: Set do
requires :b
end
end
end.to raise_error Grape::Exceptions::UnsupportedGroupTypeError
end
end
end
2 changes: 1 addition & 1 deletion spec/grape/validations/validators/values_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class API < Grape::API
end

params do
optional :optional do
optional :optional, type: Array do
requires :type, values: %w(a b)
end
end
Expand Down
32 changes: 16 additions & 16 deletions spec/grape/validations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def define_requires_none

it 'adds to declared parameters' do
subject.params do
requires :items do
requires :items, type: Array do
requires :key
end
end
Expand Down Expand Up @@ -272,7 +272,7 @@ def define_requires_none

it 'adds to declared parameters' do
subject.params do
requires :items do
requires :items, type: Array do
requires :key
end
end
Expand All @@ -283,7 +283,7 @@ def define_requires_none
context 'group' do
before do
subject.params do
group :items do
group :items, type: Array do
requires :key
end
end
Expand All @@ -306,7 +306,7 @@ def define_requires_none

it 'adds to declared parameters' do
subject.params do
group :items do
group :items, type: Array do
requires :key
end
end
Expand All @@ -319,7 +319,7 @@ def define_requires_none

before do
subject.params do
optional :items do
optional :items, type: Array do
optional :key1, type: String
optional :key2, type: String
end
Expand Down Expand Up @@ -395,9 +395,9 @@ def validate_param!(attr_name, params)
context 'validation within arrays' do
before do
subject.params do
group :children do
group :children, type: Array do
requires :name
group :parents do
group :parents, type: Array do
requires :name
end
end
Expand Down Expand Up @@ -457,7 +457,7 @@ def validate_param!(attr_name, params)
context 'with block param' do
before do
subject.params do
requires :planets do
requires :planets, type: Array do
requires :name
end
end
Expand All @@ -469,7 +469,7 @@ def validate_param!(attr_name, params)
end

subject.params do
group :stars do
group :stars, type: Array do
requires :name
end
end
Expand All @@ -482,7 +482,7 @@ def validate_param!(attr_name, params)

subject.params do
requires :name
optional :moons do
optional :moons, type: Array do
requires :name
end
end
Expand Down Expand Up @@ -549,9 +549,9 @@ def validate_param!(attr_name, params)
context 'validation within arrays with JSON' do
before do
subject.params do
group :children do
group :children, type: Array do
requires :name
group :parents do
group :parents, type: Array do
requires :name
end
end
Expand Down Expand Up @@ -630,7 +630,7 @@ def validate_param!(attr_name, params)

it 'adds to declared parameters' do
subject.params do
optional :items do
optional :items, type: Array do
requires :key
end
end
Expand Down Expand Up @@ -692,10 +692,10 @@ def validate_param!(attr_name, params)

it 'adds to declared parameters' do
subject.params do
optional :items do
optional :items, type: Array do
requires :key
optional(:optional_subitems) { requires :value }
requires(:required_subitems) { requires :value }
optional(:optional_subitems, type: Array) { requires :value }
requires(:required_subitems, type: Array) { requires :value }
end
end
expect(subject.route_setting(:declared_params)).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]])
Expand Down

0 comments on commit 0bf6fb2

Please sign in to comment.