Skip to content

Commit d962c0b

Browse files
ericproulxclaude
andcommitted
Deprecate positional options Hash in Auth DSL; use keyword arguments
`Grape::Middleware::Auth::DSL#auth`, `#http_basic` and `#http_digest` now take their options as keyword arguments. Passing a positional options Hash still works but emits a Grape.deprecator warning and is merged into the keyword options, so downstream callers keep working through the deprecation cycle. Internal delegation splats (`**options`) so the helper methods don't self-trigger the deprecation. Mirrors the `desc(description, **options)` deprecation (#2723). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e1df793 commit d962c0b

4 files changed

Lines changed: 73 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
* [#2720](https://github.com/ruby-grape/grape/pull/2720): Move declaration-coherence checks into `Grape::Validations::ValidationsSpec` - [@ericproulx](https://github.com/ericproulx).
4242
* [#2725](https://github.com/ruby-grape/grape/pull/2725): Encapsulate `Grape::Validations::Validators::Base` state behind readers; add `required?`/`allow_blank?` predicates - [@ericproulx](https://github.com/ericproulx).
4343
* [#2726](https://github.com/ruby-grape/grape/pull/2726): Reuse one `AttributesIterator` per validator and drop the unused `Enumerable` mixin - [@ericproulx](https://github.com/ericproulx).
44+
* [#2728](https://github.com/ruby-grape/grape/pull/2728): Deprecate passing a positional options Hash to `auth`/`http_basic`/`http_digest`; pass keyword arguments instead - [@ericproulx](https://github.com/ericproulx).
4445
* Your contribution here.
4546

4647
#### Fixes

UPGRADING.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,30 @@ Upgrading Grape
33

44
### Upgrading to >= 3.3
55

6+
#### `auth`, `http_basic` and `http_digest` now take keyword arguments
7+
8+
`Grape::Middleware::Auth::DSL#auth`, `#http_basic` and `#http_digest` now accept their options as keyword arguments instead of a positional `Hash`. Calls using bare keyword syntax or a block are unaffected:
9+
10+
```ruby
11+
http_basic realm: 'API' do |u, p|
12+
# ...
13+
end
14+
15+
auth :http_digest, realm: 'API', opaque: 'secret', &proc
16+
```
17+
18+
Passing a positional options `Hash` still works but is deprecated and will be removed in a future release:
19+
20+
```ruby
21+
# deprecated
22+
http_basic({ realm: 'API' })
23+
auth :http_digest, { realm: 'API', opaque: 'secret' }
24+
25+
# preferred
26+
http_basic(realm: 'API')
27+
auth :http_digest, realm: 'API', opaque: 'secret'
28+
```
29+
630
#### `Grape::Middleware::Globals` removed
731

832
`Grape::Middleware::Globals` and the three env constants it set (`Grape::Env::GRAPE_REQUEST`, `Grape::Env::GRAPE_REQUEST_HEADERS`, `Grape::Env::GRAPE_REQUEST_PARAMS`) have been deleted. The middleware was introduced in 2013 (commit `9987090b`) but never mounted by Grape's own stack — the `Grape::Request` it built is now constructed directly inside `Grape::Endpoint`. Nothing in `lib/` read those env keys.

lib/grape/middleware/auth/dsl.rb

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,27 @@ module Grape
44
module Middleware
55
module Auth
66
module DSL
7-
def auth(type = nil, options = {}, &block)
7+
def auth(type = nil, *legacy_options, **options, &block)
88
namespace_inheritable = inheritable_setting.namespace_inheritable
99
return namespace_inheritable[:auth] unless type
1010

11+
options = merge_legacy_auth_options(:auth, legacy_options, options)
1112
namespace_inheritable[:auth] = options.reverse_merge(type: type.to_sym, proc: block)
1213
use Grape::Middleware::Auth::Base, namespace_inheritable[:auth]
1314
end
1415

1516
# Add HTTP Basic authorization to the API.
1617
#
17-
# @param [Hash] options A hash of options.
18-
# @option options [String] :realm "API Authorization" The HTTP Basic realm.
19-
def http_basic(options = {}, &)
18+
# @param options [Hash] a hash of options
19+
# @option options [String] :realm "API Authorization" the HTTP Basic realm
20+
def http_basic(*legacy_options, **options, &)
21+
options = merge_legacy_auth_options(:http_basic, legacy_options, options)
2022
options[:realm] ||= 'API Authorization'
21-
auth(:http_basic, options, &)
23+
auth(:http_basic, **options, &)
2224
end
2325

24-
def http_digest(options = {}, &)
26+
def http_digest(*legacy_options, **options, &)
27+
options = merge_legacy_auth_options(:http_digest, legacy_options, options)
2528
options[:realm] ||= 'API Authorization'
2629

2730
if options[:realm].respond_to?(:values_at)
@@ -30,7 +33,19 @@ def http_digest(options = {}, &)
3033
options[:opaque] ||= 'secret'
3134
end
3235

33-
auth(:http_digest, options, &)
36+
auth(:http_digest, **options, &)
37+
end
38+
39+
private
40+
41+
# @deprecated Passing a positional options Hash is deprecated; pass
42+
# keyword arguments instead. Kept so downstream callers keep working
43+
# through the deprecation cycle.
44+
def merge_legacy_auth_options(method_name, legacy_options, options)
45+
return options if legacy_options.empty?
46+
47+
Grape.deprecator.warn("Passing a positional options Hash to `#{method_name}` is deprecated. Pass keyword arguments instead.")
48+
legacy_options.first.merge(options)
3449
end
3550
end
3651
end

spec/grape/middleware/auth/dsl_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,30 @@
5757
end
5858
end
5959
end
60+
61+
describe 'deprecated positional options Hash' do
62+
it 'deprecates a positional Hash for `auth` but still works when silenced' do
63+
expect { subject.auth :http_digest, { realm: 'r', opaque: 'o' }, &block }
64+
.to raise_error(ActiveSupport::DeprecationException, /positional options Hash to `auth`/)
65+
66+
Grape.deprecator.silence { subject.auth :http_digest, { realm: 'r', opaque: 'o' }, &block }
67+
expect(subject.auth).to eq(realm: 'r', opaque: 'o', type: :http_digest, proc: block)
68+
end
69+
70+
it 'deprecates a positional Hash for `http_basic` but still works when silenced' do
71+
expect { subject.http_basic({ realm: 'my_realm' }, &block) }
72+
.to raise_error(ActiveSupport::DeprecationException, /positional options Hash to `http_basic`/)
73+
74+
Grape.deprecator.silence { subject.http_basic({ realm: 'my_realm' }, &block) }
75+
expect(subject.auth).to eq(realm: 'my_realm', type: :http_basic, proc: block)
76+
end
77+
78+
it 'deprecates a positional Hash for `http_digest` but still works when silenced' do
79+
expect { subject.http_digest({ realm: 'my_realm' }, &block) }
80+
.to raise_error(ActiveSupport::DeprecationException, /positional options Hash to `http_digest`/)
81+
82+
Grape.deprecator.silence { subject.http_digest({ realm: 'my_realm' }, &block) }
83+
expect(subject.auth).to eq(realm: 'my_realm', opaque: 'secret', type: :http_digest, proc: block)
84+
end
85+
end
6086
end

0 commit comments

Comments
 (0)