Skip to content

Commit

Permalink
Add validator 'declared_only' to reject undeclared params
Browse files Browse the repository at this point in the history
  • Loading branch information
Joe Faber committed Apr 4, 2017
1 parent f4624bf commit 11bca89
Show file tree
Hide file tree
Showing 9 changed files with 361 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* [#1568](https://github.com/ruby-grape/grape/pull/1568): Add `proc` option to `values` validator to allow custom checks - [@jlfaber](https://github.com/jlfaber).
* [#1575](https://github.com/ruby-grape/grape/pull/1575): Include nil values for missing nested params in declared - [@thogg4](https://github.com/thogg4).
* [#1585](https://github.com/ruby-grape/grape/pull/1585): Bugs in declared method - make sure correct options var is used and respect include missing for non children params - [@thogg4](https://github.com/thogg4).
* [#1605](https://github.com/ruby-grape/grape/pull/1605): Add `declared_only` validator to reject undeclared keys within block- [@jlfaber](https://github.com/jlfaber).
* Your contribution here.

#### Fixes
Expand Down
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1251,7 +1251,20 @@ params do
end
```

#### Nested `mutually_exclusive`, `exactly_one_of`, `at_least_one_of`, `all_or_none_of`
#### `declared_only`

The method 'declared_only' may be used within any block to ensure that no undeclared parameters are allowed.

```ruby
params do
optional :beer
optional :wine
optional :juice
declared_only
end
```

#### Nested `mutually_exclusive`, `exactly_one_of`, `at_least_one_of`, `all_or_none_of`, `declared_only`

All of these methods can be used at any nested level.

Expand All @@ -1274,11 +1287,13 @@ params do
optional :icecream
mutually_exclusive :cake, :icecream
end
optional :recipe, type: Hash do
optional :recipes, type: Array do
optional :oil
optional :meat
all_or_none_of :oil, :meat
declared_only
end
declared_only
end
```

Expand Down
1 change: 1 addition & 0 deletions lib/grape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ module ServeFile
require 'grape/validations/validators/default'
require 'grape/validations/validators/exactly_one_of'
require 'grape/validations/validators/mutual_exclusion'
require 'grape/validations/validators/declared_only'
require 'grape/validations/validators/presence'
require 'grape/validations/validators/regexp'
require 'grape/validations/validators/values'
Expand Down
6 changes: 6 additions & 0 deletions lib/grape/dsl/parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ def all_or_none_of(*attrs)
validates(attrs, all_or_none_of: { value: true, message: extract_message_option(attrs) })
end

# Require that only declared params are present.
# @param (see #mutually_exclusive)
def declared_only(*attrs)
validates(attrs, declared_only: { value: true, message: extract_message_option(attrs) })
end

# Define a block of validations which should be applied if and only if
# the given parameter is present. The parameters are not nested.
# @param attr [Symbol] the parameter which, if present, triggers the
Expand Down
1 change: 1 addition & 0 deletions lib/grape/locale/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ 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'
declared_only: 'is not a declared parameter'
missing_group_type: 'group type is required'
unsupported_group_type: 'group type must be Array, Hash, JSON or Array[JSON]'
invalid_message_body:
Expand Down
2 changes: 1 addition & 1 deletion lib/grape/validations/params_scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Grape
module Validations
class ParamsScope
attr_accessor :element, :parent, :index
attr_reader :type
attr_reader :type, :declared_params

include Grape::DSL::Parameters

Expand Down
25 changes: 25 additions & 0 deletions lib/grape/validations/validators/declared_only.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module Grape
module Validations
require 'grape/validations/validators/multiple_params_base'
class DeclaredOnlyValidator < MultipleParamsBase
attr_reader :extra_params

def validate!(params)
super
if extra_params_are_present
raise Grape::Exceptions::Validation, params: extra_params, message: message(:declared_only)
end
params
end

private

def extra_params_are_present
scoped_params.any? do |resource_params|
@extra_params = undeclared_keys(resource_params)
!@extra_params.empty?
end
end
end
end
end
8 changes: 8 additions & 0 deletions lib/grape/validations/validators/multiple_params_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ def keys_in_common(resource_params)
(all_keys & resource_params.stringify_keys.keys).map(&:to_s)
end

def undeclared_keys(resource_params)
return [] unless resource_params.is_a?(Hash)
allowed_keys = @scope.declared_params.map do |k|
k.is_a?(Hash) ? k.keys.first.to_s : k.to_s
end
(resource_params.stringify_keys.keys - allowed_keys)
end

def all_keys
attrs.map(&:to_s)
end
Expand Down
Loading

0 comments on commit 11bca89

Please sign in to comment.