ruby-grape / grape

An opinionated framework for creating REST-like APIs in Ruby.
http://www.ruby-grape.org
MIT License
9.86k stars 1.22k forks source link

undefined method `rewind' for #<Rack::Lint::Wrapper::InputWrapper w/Rack >= 3.0 #2388

Open andrius opened 7 months ago

andrius commented 7 months ago

I use a simple ruby (not rails) API with grape, grape-entiry and grape-swagger gems, along with the mongoid. For POST or PUT endpoints it does throw the following error:

NoMethodError: undefined method `rewind' for #<Rack::Lint::Wrapper::InputWrapper:0x0000ffffa610b728 @input=#<StringIO:0x0000ffffa610bf48>> (NoMethodError)

        input.rewind
             ^^^^^^^
    /usr/local/bundle/gems/grape-2.0.0/lib/grape/middleware/formatter.rb:87:in `read_body_input'
    /usr/local/bundle/gems/grape-2.0.0/lib/grape/middleware/formatter.rb:20:in `before'
    /usr/local/bundle/gems/grape-2.0.0/lib/grape/middleware/base.rb:34:in `call!'
    /usr/local/bundle/gems/grape-2.0.0/lib/grape/middleware/base.rb:29:in `call'
    /usr/local/bundle/gems/grape-2.0.0/lib/grape/middleware/error.rb:39:in `block in call!'
    /usr/local/bundle/gems/grape-2.0.0/lib/grape/middleware/error.rb:38:in `catch'
    /usr/local/bundle/gems/grape-2.0.0/lib/grape/middleware/error.rb:38:in `call!'
    /usr/local/bundle/gems/grape-2.0.0/lib/grape/middleware/base.rb:29:in `call'
    /usr/local/bundle/gems/rack-3.0.8/lib/rack/head.rb:15:in `call'

Based on online search I've found that similar issues were long time ago and were fixed, but here it is. Any ideas how to fix it? Happy to share more details or code snippets!

dblock commented 7 months ago

This is caused by lack of rewind on the input in Rack. Typically that would extend https://github.com/rack/rack/blob/main/lib/rack/rewindable_input.rb, but it looks like Rack::Lint::Wrapper::InputWrapper doesn't have that. What is the actual setup you have that makes the content that type? Try building a minimal repro?

andrius commented 7 months ago

Thank you. I've included minimal example in this gist: https://gist.github.com/andrius/50e2965a9b0936a7c76f9d7f77bdc2a7

To run:

docker compose build && docker compose run --rm --interactive --service-ports api

To test:

curl -X POST \
  'http://localhost:3000/v1/users' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"name": "foo", "lastname": "bar", "email": "foo@bar.foo", "telephone": "+1234567890", "role": "user"}'
dblock commented 7 months ago

Found the issue, https://github.com/rack/rack/discussions/1972. Adding use Rack::RewindableInput::Middleware fixed the issue for me, so would downgrading to Rack 2.x.

require_relative 'api'
use Rack::RewindableInput::Middleware
run API::Root

We should do something about this in Grape. Would you like to help @andrius? We have https://github.com/ruby-grape/grape/tree/master/spec/integration/rack/v3 and https://github.com/ruby-grape/grape/blob/master/gemfiles/rack_3_0.gemfile, but we're not catching this error. The first thing to figure out is how to reproduce it in CI, then we can see whether we should just recommend including this middleware manually, or more likely have to write some code to include it when Rack version is >= 3.0.

andrius commented 7 months ago

Your suggestion with use Rack::RewindableInput::Middleware helped and API start working!

Would you like to help @andrius?

I will try but it will take time. Just check'ed the GitHub workflows

ericproulx commented 1 month ago

Should be fixed in the latest release. Could you test it out ?