hanami / api

Minimal, lightweight, fastest Ruby framework for HTTP APIs.

Home Page:https://hanamirb.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Middleware with named arguments not initialized properly – wrong number of arguments

ahx opened this issue · comments

When trying to use a middleware that uses named arguments like this:

class TellQuotaMiddleware
  def initialize(app, quota:)
    @app = app
    @quota = quota
  end

  def call(env)
    status, headers, body = @app.call(env)
    headers["X-API-Rate-Limit-Quota"] = @quota

    [status, headers, body]
  end
end

It fails with

ArgumentError:
       wrong number of arguments (given 2, expected 1; required keyword: quota)

See #34 for a failing test.

I don't know if it is allowed to use named arguments as options for rack middlewares, but I did not find anything that says the opposite. So I think it's allowed.

@ahx This is a Rack limitation. Rack::Builder#use doesn't support keyword arguments (API docs).

Indeed, if you look at the stack trace, the error is happening in the Rack codebase:

Failures:

  1) Hanami::API Rack middleware with complex app uses Rack middleware
     Failure/Error:
       def initialize(app, quota:)
         @app = app
         @quota = quota
       end

     ArgumentError:
       wrong number of arguments (given 2, expected 1; required keyword: quota)
     # ./spec/integration/hanami/api/middleware_spec.rb:66:in `initialize'
     # /Users/jodosha/.gem/ruby/3.1.0/gems/rack-2.2.3/lib/rack/builder.rb:158:in `new'
     # /Users/jodosha/.gem/ruby/3.1.0/gems/rack-2.2.3/lib/rack/builder.rb:158:in `block in use'
     # /Users/jodosha/.gem/ruby/3.1.0/gems/rack-2.2.3/lib/rack/builder.rb:235:in `block in to_app'
     # /Users/jodosha/.gem/ruby/3.1.0/gems/rack-2.2.3/lib/rack/builder.rb:235:in `each'
     # /Users/jodosha/.gem/ruby/3.1.0/gems/rack-2.2.3/lib/rack/builder.rb:235:in `inject'
     # /Users/jodosha/.gem/ruby/3.1.0/gems/rack-2.2.3/lib/rack/builder.rb:235:in `to_app'
     # ./lib/hanami/api/middleware/app.rb:27:in `block in initialize'
     # ./lib/hanami/api/middleware/app.rb:18:in `each'
     # ./lib/hanami/api/middleware/app.rb:18:in `initialize'
     # ./lib/hanami/api/middleware.rb:47:in `new'
     # ./lib/hanami/api/middleware.rb:47:in `finalize'
     # ./lib/hanami/api/router.rb:40:in `to_rack_app'
     # ./lib/hanami/api/dsl.rb:105:in `freeze'
     # ./lib/hanami/api/dsl.rb:99:in `initialize'
     # ./spec/integration/hanami/api/middleware_spec.rb:243:in `new'
     # ./spec/integration/hanami/api/middleware_spec.rb:243:in `block (4 levels) in <top (required)>'
     # ./spec/integration/hanami/api/middleware_spec.rb:5:in `block (3 levels) in <top (required)>'
     # ./spec/integration/hanami/api/middleware_spec.rb:247:in `block (4 levels) in <top (required)>'

The correct syntax would be

class TellQuotaMiddleware
  def initialize(app, quota)
    @app = app
    @quota = quota
  end
end
use TellQuotaMiddleware, 100

Thanks for looking into this, @jodosha .