Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Corrected the endpoint parameter name generation. #2189

Merged
merged 5 commits into from
Sep 15, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* [#2176](https://github.com/ruby-grape/grape/pull/2176): Fix: OPTIONS fails if matching all routes - [@myxoh](https://github.com/myxoh).
* [#2177](https://github.com/ruby-grape/grape/pull/2177): Fix: `default` validator fails if preceded by `as` validator - [@Catsuko](https://github.com/Catsuko).
* [#2180](https://github.com/ruby-grape/grape/pull/2180): Call `super` in `API.inherited` - [@yogeshjain999](https://github.com/yogeshjain999).
* [#2189](https://github.com/ruby-grape/grape/pull/2189): Corrected the endpoint parameter name generation - [@Jack12816](https://github.com/Jack12816).
* [#2189](https://github.com/ruby-grape/grape/pull/2189): Fix: rename parameters when using `:as` (behaviour and grape-swagger documentation) - [@Jack12816](https://github.com/Jack12816).
* Your contribution here.

### 1.5.3 (2021/03/07)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ Grape allows you to access only the parameters that have been declared by your `

* Filter out the params that have been passed, but are not allowed.
* Include any optional params that are declared but not passed.
* Perform any parameter renaming on the resulting hash.

Consider the following API endpoint:

Expand Down
56 changes: 55 additions & 1 deletion UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,64 @@
Upgrading Grape
===============

### Upgrading to >= 1.5.4
Jack12816 marked this conversation as resolved.
Show resolved Hide resolved

#### Parameter renaming with :as

Prior to 1.5.4 the [parameter
renaming](https://github.com/ruby-grape/grape#renaming) with `:as` was directly
touching the request payload
([`#params`](https://github.com/ruby-grape/grape#parameters)) while duplicating
the old and the new key to be both available in the hash. This allowed clients
to bypass any validation in case they knew the internal name of the parameter.
Unfortunately, in combination with
[grape-swagger](https://github.com/ruby-grape/grape-swagger) the internal name
(name set with `:as`) of the parameters were documented.

From now on the parameter renaming is not anymore done automatically in the
Jack12816 marked this conversation as resolved.
Show resolved Hide resolved
request payload, but only when using the
[`#declared(params)`](https://github.com/ruby-grape/grape#declared) parameters
helper. This stops confusing validation/coercion behavior.

Here comes an illustration of the old and new behaviour as code:

```ruby
# (1) Rename a to b, while client sends +a+
optional :a, type: Integer, as: :b
params = { a: 1 }
declared(params, include_missing: false)
# expected => { b: 1 }
# actual => { b: 1 }

# (2) Rename a to b, while client sends +b+
optional :a, type: Integer, as: :b, values: [1, 2, 3]
params = { b: '5' }
declared(params, include_missing: false)
# expected => { } (>= 1.5.4)
# actual => { b: '5' } (uncasted, unvalidated, <= 1.5.3)
```

Another implication of this is the dependent parameter resolution. Prior to
Jack12816 marked this conversation as resolved.
Show resolved Hide resolved
1.5.4 the following code produced an `Grape::Exceptions::UnknownParameter`
because `:a` was replace by `:b`:

```ruby
params do
optional :a, as: :b
given :a do # (<= 1.5.3 you had to reference +:b+ here to make it work)
requires :c
end
end
```

This code now works without any errors, as the renaming is just an internal
behaviour of the `#declared(params)` parameter helper.

See [#2189](https://github.com/ruby-grape/grape/pull/2189) for more information.

### Upgrading to >= 1.5.3

### Nil value and coercion
#### Nil value and coercion

Prior to 1.2.5 version passing a `nil` value for a parameter with a custom coercer would invoke the coercer, and not passing a parameter would not invoke it.
This behavior was not tested or documented. Version 1.3.0 quietly changed this behavior, in such that `nil` values skipped the coercion. Version 1.5.3 fixes and documents this as follows:
Expand Down
4 changes: 2 additions & 2 deletions lib/grape/dsl/inside_route.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def declared_hash(passed_params, options, declared_params, params_nested_path)
params_nested_path_dup << declared_parent_param.to_s
next unless options[:include_missing] || passed_params.key?(declared_parent_param)

rename_path = params_nested_path.dup + [declared_parent_param.to_s]
rename_path = params_nested_path + [declared_parent_param.to_s]
renamed_param_name = renamed_params[rename_path]

memo_key = optioned_param_key(renamed_param_name || declared_parent_param, options)
Expand All @@ -72,7 +72,7 @@ def declared_hash(passed_params, options, declared_params, params_nested_path)
# Find its value or set it to nil.
next unless options[:include_missing] || passed_params.key?(declared_param)

rename_path = params_nested_path.dup + [declared_param.to_s]
rename_path = params_nested_path + [declared_param.to_s]
renamed_param_name = renamed_params[rename_path]

memo_key = optioned_param_key(renamed_param_name || declared_param, options)
Expand Down
20 changes: 10 additions & 10 deletions lib/grape/validations/params_scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class ParamsScope
# @param opts [Hash] options for this scope
# @option opts :element [Symbol] the element that contains this scope; for
# this to be relevant, @parent must be set
# @option opts :rename [Symbol, nil] whenever this scope should be
# renamed and to what
# @option opts :element_renamed [Symbol, nil] whenever this scope should
# be renamed and to what, given +nil+ no renaming is done
# @option opts :parent [ParamsScope] the scope containing this scope
# @option opts :api [API] the API endpoint to modify
# @option opts :optional [Boolean] whether or not this scope needs to have
Expand All @@ -26,7 +26,7 @@ class ParamsScope
# @yield the instance context, open for parameter definitions
def initialize(opts, &block)
@element = opts[:element]
@rename = opts[:rename]
@element_renamed = opts[:element_renamed]
@parent = opts[:parent]
@api = opts[:api]
@optional = opts[:optional] || false
Expand Down Expand Up @@ -211,12 +211,12 @@ def new_scope(attrs, optional = false, &block)
end

self.class.new(
api: @api,
element: attrs.first,
rename: attrs[1][:as],
parent: self,
optional: optional,
type: type || Array,
api: @api,
element: attrs.first,
element_renamed: attrs[1][:as],
parent: self,
optional: optional,
type: type || Array,
&block
)
end
Expand Down Expand Up @@ -256,7 +256,7 @@ def new_group_scope(attrs, &block)

# Pushes declared params to parent or settings
def configure_declared_params
push_renamed_param(full_path, @rename) if @rename
push_renamed_param(full_path, @element_renamed) if @element_renamed

if nested?
@parent.push_declared_params [element => @declared_params]
Expand Down