-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Router#cascade? undefined method `[]' for nil:NilClass #1966
Description
Grape is raising an NoMethodError when implementing a really basic API endpoint.
What I expect
Basic requests to not raise errors.
What actually happens
It raises NoMethodError. Sample output from Minitest (described below):
1) Error:
GrapeTest#test_api_success:
NoMethodError: undefined method `[]' for nil:NilClass
/usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:164:in `cascade?'
/usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:95:in `transaction'
/usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:72:in `identity'
/usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:57:in `block in call'
/usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:137:in `with_optimization'
/usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:56:in `call'
/usr/local/bundle/gems/grape-1.2.5/lib/grape/api/instance.rb:165:in `call'
/usr/local/bundle/gems/grape-1.2.5/lib/grape/api/instance.rb:69:in `call!'
/usr/local/bundle/gems/grape-1.2.5/lib/grape/api/instance.rb:64:in `call'
/usr/local/bundle/gems/grape-1.2.5/lib/grape/api.rb:66:in `call'
/usr/local/bundle/gems/rack-test-1.1.0/lib/rack/mock_session.rb:29:in `request'
/usr/local/bundle/gems/rack-test-1.1.0/lib/rack/test.rb:266:in `process_request'
/usr/local/bundle/gems/rack-test-1.1.0/lib/rack/test.rb:129:in `custom_request'
/usr/local/bundle/gems/rack-test-1.1.0/lib/rack/test.rb:58:in `get'
/usr/local/lib/ruby/2.3.0/forwardable.rb:202:in `get'
/app/test/contrib/grape/request_test.rb:25:in `test_api_success'
Steps to reproduce
Dependencies from Gemfile.lock
grape (1.2.5)
activesupport
builder
mustermann-grape (~> 1.0.0)
rack (>= 1.3.0)
rack-accept
virtus (>= 1.0.0)
rack (2.1.0)
rack-accept (0.4.5)
rack (>= 0.4)
rack-protection (2.0.8.1)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
mustermann (1.1.1)
ruby2_keywords (~> 0.0.1)
mustermann-grape (1.0.1)
mustermann (>= 1.0.0)
virtus (1.0.5)
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
Minitest:
require 'rack/test'
require 'grape'
class TestingAPI < Grape::API
namespace :base do
desc 'Returns a success message'
get :success do
'OK'
end
end
end
class GrapeTest < MiniTest::Test
include Rack::Test::Methods
def app
TestingAPI
end
def test_api_success
get '/base/success'
assert last_response.ok?
assert_equal('OK', last_response.body)
end
end
Other thoughts
This did happen after updating my Gemfile.lock, which showed the following being updated:
Installing ruby2_keywords 0.0.2
Installing mustermann 1.1.1
Installing mustermann-grape 1.0.1
Between looking at the changes in those repos and the stacktrace, I didn't see anything that would explain it.
Digging deeper into the Grape code, what I found in middleware/base.rb was:
begin
@app_response = @app.call(@env)
ensure
begin
after_response = after
rescue StandardError => e
warn "caught error of type #{e.class} in after callback inside #{self.class.name} : #{e.message}"
raise e
end
end
response = after_response || @app_responseRunning this through my test, @app_response was [200, {}, ["OK"]], and after_response was derived from ["/usr/local/bundle/gems/grape-1.2.5/lib/grape/middleware/formatter.rb", 21] which returned:
#<Rack::Response:0x0000561ee6ee7a40
@block=nil,
@body=["OK"],
@buffered=false,
@header={"Content-Type"=>"text/plain"},
@length=0,
@status=200,
@writer=#<Method: Rack::Response(Rack::Response::Helpers)#append>>
So it would select after_response which would return #<Rack::Response> to rack/head.rb which parsed it into an Array as [#<Rack::Response>, nil nil].
This Array is then eventually passed to Router#cascade? where it would fail because the second argument is nil:
def cascade?(response)
response && response[1][Grape::Http::Headers::X_CASCADE] == 'pass'
end