Grape is raising an NoMethodError when implementing a really basic API endpoint.
Basic requests to not raise errors.
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'
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
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_response
Running 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
For reference, this is the commit that removes the ability of Rack::Respond to be behave like an array (released Jan 10th 2020 in Rack v2.1.0): https://github.com/rack/rack/commit/72959ebc2f300f3b2ccb7ae2aae9f199e611dfb6
Thanks, does anyone care to try and fix this in grape to be back and forward compatible?
https://github.com/ruby-grape/grape/blob/v1.2.5/lib/grape/router.rb#L163
I'll see what I can do.
https://github.com/ruby-grape/grape/pull/1956 already fixed this and tests in on multiple versions of rack which all pass.
Wasn't aware of this fix; thanks @ioquatix!
Great, thanks @ioquatix.
We have #1958. Maybe someone can jump on it soon.
@delner you might downgrade Rack to 2.0.8, later upgrade Grape to 1.3.0 :slightly_smiling_face:
@delner Grape 1.3.0 was released, feel free to upgrade :rocket: :smile:
Thanks @dnesteryuk !
Most helpful comment
@delner Grape 1.3.0 was released, feel free to upgrade :rocket: :smile: