Open
Description
The test added by this commit fails with
Grape::API::Helpers defines parameters
Failure/Error: return unless options[:include_missing] || passed_params.key?(declared_param)
NoMethodError:
undefined method 'key?' for an instance of String
# ./lib/grape/dsl/inside_route.rb:82:in 'Grape::DSL::InsideRoute::PostBeforeFilter#declared_hash_attr'
# ./lib/grape/dsl/inside_route.rb:57:in 'block in Grape::DSL::InsideRoute::PostBeforeFilter#declared_hash'
# ./lib/grape/dsl/inside_route.rb:54:in 'Array#each'
# ./lib/grape/dsl/inside_route.rb:54:in 'Enumerable#each_with_object'
# ./lib/grape/dsl/inside_route.rb:54:in 'Grape::DSL::InsideRoute::PostBeforeFilter#declared_hash'
# ./lib/grape/dsl/inside_route.rb:35:in 'Grape::DSL::InsideRoute::PostBeforeFilter#declared'
# ./lib/grape/dsl/inside_route.rb:49:in 'block in Grape::DSL::InsideRoute::PostBeforeFilter#declared_array'
# ./lib/grape/dsl/inside_route.rb:48:in 'Array#map'
# ./lib/grape/dsl/inside_route.rb:48:in 'Grape::DSL::InsideRoute::PostBeforeFilter#declared_array'
# ./lib/grape/dsl/inside_route.rb:33:in 'Grape::DSL::InsideRoute::PostBeforeFilter#declared'
# ./lib/grape/dsl/inside_route.rb:76:in 'block (2 levels) in Grape::DSL::InsideRoute::PostBeforeFilter#declared_hash_attr'
# ./lib/grape/dsl/inside_route.rb:99:in 'Grape::DSL::InsideRoute::PostBeforeFilter#handle_passed_param'
# ./lib/grape/dsl/inside_route.rb:75:in 'block in Grape::DSL::InsideRoute::PostBeforeFilter#declared_hash_attr'
# ./lib/grape/dsl/inside_route.rb:64:in 'Hash#each_pair'
# ./lib/grape/dsl/inside_route.rb:64:in 'Grape::DSL::InsideRoute::PostBeforeFilter#declared_hash_attr'
# ./lib/grape/dsl/inside_route.rb:57:in 'block in Grape::DSL::InsideRoute::PostBeforeFilter#declared_hash'
# ./lib/grape/dsl/inside_route.rb:54:in 'Array#each'
# ./lib/grape/dsl/inside_route.rb:54:in 'Enumerable#each_with_object'
# ./lib/grape/dsl/inside_route.rb:54:in 'Grape::DSL::InsideRoute::PostBeforeFilter#declared_hash'
# ./lib/grape/dsl/inside_route.rb:35:in 'Grape::DSL::InsideRoute::PostBeforeFilter#declared'
# ./spec/grape/api/array_issue_spec.rb:13:in 'block (4 levels) in <top (required)>'
# ./lib/grape/endpoint.rb:62:in 'UnboundMethod#bind_call'
# ./lib/grape/endpoint.rb:62:in 'block (2 levels) in Grape::Endpoint.generate_api_method'
# /usr/local/bundle/gems/ruby/3.4.0/gems/activesupport-8.0.2/lib/active_support/notifications.rb:212:in 'ActiveSupport::Notifications.instrument'
# ./lib/grape/endpoint.rb:61:in 'block in Grape::Endpoint.generate_api_method'
# ./lib/grape/endpoint.rb:287:in 'Grape::Endpoint#execute'
# ./lib/grape/endpoint.rb:267:in 'block in Grape::Endpoint#run'
# /usr/local/bundle/gems/ruby/3.4.0/gems/activesupport-8.0.2/lib/active_support/notifications.rb:212:in 'ActiveSupport::Notifications.instrument'
# ./lib/grape/endpoint.rb:250:in 'Grape::Endpoint#run'
# ./lib/grape/endpoint.rb:394:in 'block in Grape::Endpoint#build_stack'
# ./lib/grape/middleware/base.rb:33:in 'Grape::Middleware::Base#call!'
# ./lib/grape/middleware/base.rb:26:in 'Grape::Middleware::Base#call'
# ./lib/grape/middleware/error.rb:34:in 'block in Grape::Middleware::Error#call!'
# ./lib/grape/middleware/error.rb:34:in 'Kernel#catch'
# ./lib/grape/middleware/error.rb:34:in 'Grape::Middleware::Error#call!'
# ./lib/grape/middleware/base.rb:26:in 'Grape::Middleware::Base#call'
# /usr/local/bundle/gems/ruby/3.4.0/gems/rack-3.1.12/lib/rack/head.rb:15:in 'Rack::Head#call'
# ./lib/grape/endpoint.rb:225:in 'Grape::Endpoint#call!'
# ./lib/grape/endpoint.rb:219:in 'Grape::Endpoint#call'
# ./lib/grape/router/route.rb:27:in 'Grape::Router::Route#exec'
# ./lib/grape/router.rb:139:in 'Grape::Router#process_route'
# ./lib/grape/router.rb:86:in 'block in Grape::Router#identity'
# ./lib/grape/router.rb:119:in 'Grape::Router#transaction'
# ./lib/grape/router.rb:84:in 'Grape::Router#identity'
# ./lib/grape/router.rb:68:in 'block in Grape::Router#call'
# ./lib/grape/router.rb:155:in 'Grape::Router#with_optimization'
# ./lib/grape/router.rb:67:in 'Grape::Router#call'
# ./lib/grape/api/instance.rb:164:in 'Grape::API::Instance#call'
# ./lib/grape/api/instance.rb:68:in 'Grape::API::Instance.call!'
# ./lib/grape/api/instance.rb:63:in 'Grape::API::Instance.call'
# /usr/local/bundle/gems/ruby/3.4.0/gems/rack-test-2.2.0/lib/rack/test.rb:360:in 'Rack::Test::Session#process_request'
# /usr/local/bundle/gems/ruby/3.4.0/gems/rack-test-2.2.0/lib/rack/test.rb:163:in 'Rack::Test::Session#custom_request'
# /usr/local/bundle/gems/ruby/3.4.0/gems/rack-test-2.2.0/lib/rack/test.rb:112:in 'Rack::Test::Session#post'
# ./spec/grape/api/array_issue_spec.rb:28:in 'block (2 levels) in <top (required)>'
Somehow1, params
contains {"z" => [""]}
.
I'm new to ruby and I'm not sure how Grape actually works. My current assumptions are that Grape validates params
regardless of if declared
is called or not; declared
is only used to extract declared params according to the params schema. With that it mind, it feels like validation let through an array that shouldn't have passed validation.
Applying
diff --git a/spec/grape/api/array_issue_spec.rb b/spec/grape/api/array_issue_spec.rb
index d8ff4af1..5f1a5bbf 100644
--- a/spec/grape/api/array_issue_spec.rb
+++ b/spec/grape/api/array_issue_spec.rb
@@ -4,7 +4,7 @@ describe Grape::API::Helpers do
subject do
Class.new(Grape::API) do
params do
- optional :z, type: Array do
+ requires :z, type: Array do
requires :a, type: Integer
end
end
result in a 400 status code. This points to an issue specific to the use of both optional
and type: Array
.
Footnotes
-
I suspect it has to do with how form encoded bodies can't effectively encode an empty array that's not absent. ↩