Skip to content

Commit 3a0233a

Browse files
ericproulxdblock
andauthored
New feature : linting (#2557)
* Add linting feature through Grape.config and `lint_api!` method Add spec All specs are now linted * Remove error message for Lint::Error * Add ruby 3.1 to 3.2 to spec integrations Add `yaml-dev` in Dockerfile * Rename `lint_api!` to `lint!` * Revert test.yml * Add README.md and CHANGELOG.md Fix typo in UPGRADING.md * Fix CHANGELOG * Use `lint!` in rails spec * Fix api_spec lint with ensure --------- Co-authored-by: Daniel (dB.) Doubrovkine <[email protected]>
1 parent 485b90d commit 3a0233a

File tree

10 files changed

+63
-3
lines changed

10 files changed

+63
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* [#2554](https://github.com/ruby-grape/grape/pull/2554): Remove `Grape::Http::Headers` and `Grape::Util::Lazy::Object` - [@ericproulx](https://github.com/ericproulx).
1313
* [#2556](https://github.com/ruby-grape/grape/pull/2556): Remove unused `Grape::Request::DEFAULT_PARAMS_BUILDER` constant - [@eriklovmo](https://github.com/eriklovmo).
1414
* [#2558](https://github.com/ruby-grape/grape/pull/2558): Add Ruby's option `enable_frozen_string_literal` in CI - [@ericproulx](https://github.com/ericproulx).
15+
* [#2557](https://github.com/ruby-grape/grape/pull/2557): Add lint! - [@ericproulx](https://github.com/ericproulx).
1516
* Your contribution here.
1617

1718
#### Fixes

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
- [Header](#header)
2929
- [Accept-Version Header](#accept-version-header)
3030
- [Param](#param)
31+
- [Linting](#linting)
32+
- [Bug in Rack::ETag under Rack 3.X](#bug-in-racketag-under-rack-3x)
3133
- [Describing Methods](#describing-methods)
3234
- [Configuration](#configuration)
3335
- [Parameters](#parameters)
@@ -650,6 +652,27 @@ version 'v1', using: :param, parameter: 'v'
650652
curl http://localhost:9292/statuses/public_timeline?v=v1
651653

652654

655+
## Linting
656+
657+
You can check whether your API is in conformance with the [Rack's specification](https://github.com/rack/rack/blob/main/SPEC.rdoc) by calling `lint!` at the API level or through [configuration](#configuration).
658+
659+
```ruby
660+
class Api < Grape::API
661+
lint!
662+
end
663+
```
664+
```ruby
665+
Grape.configure do |config|
666+
config.lint = true
667+
end
668+
```
669+
```ruby
670+
Grape.config.lint = true
671+
```
672+
673+
### Bug in Rack::ETag under Rack 3.X
674+
If you're using Rack 3.X and the `Rack::Etag` middleware (used by [Rails](https://guides.rubyonrails.org/rails_on_rack.html#inspecting-middleware-stack)), a [bug](https://github.com/rack/rack/pull/2324) related to linting has been fixed in [3.1.13](https://github.com/rack/rack/blob/v3.1.13/CHANGELOG.md#3113---2025-04-13) and [3.0.15](https://github.com/rack/rack/blob/v3.1.13/CHANGELOG.md#3015---2025-04-13) respectively.
675+
653676
## Describing Methods
654677

655678
You can add a description to API methods and namespaces. The description would be used by [grape-swagger][grape-swagger] to generate swagger compliant documentation.

UPGRADING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ When using together with `Grape::Extensions::Hash::ParamBuilder`, `route_param`
130130
This was a regression introduced by [#2326](https://github.com/ruby-grape/grape/pull/2326) in Grape v1.8.0.
131131

132132
```ruby
133-
grape.configure do |config|
133+
Grape.configure do |config|
134134
config.param_builder = Grape::Extensions::Hash::ParamBuilder
135135
end
136136

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ENV RUBYOPT --enable-frozen-string-literal --yjit
77
ENV LD_PRELOAD libjemalloc.so.2
88
ENV MALLOC_CONF dirty_decay_ms:1000,narenas:2,background_thread:true
99

10-
RUN apk add --update --no-cache make gcc git libc-dev gcompat jemalloc && \
10+
RUN apk add --update --no-cache make gcc git libc-dev yaml-dev gcompat jemalloc && \
1111
gem update --system && gem install bundler
1212

1313
WORKDIR $LIB_PATH

lib/grape.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def self.deprecator
7575

7676
configure do |config|
7777
config.param_builder = :hash_with_indifferent_access
78+
config.lint = false
7879
config.compile_methods!
7980
end
8081
end

lib/grape/dsl/routing.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ def do_not_route_options!
8181
namespace_inheritable(:do_not_route_options, true)
8282
end
8383

84+
def lint!
85+
namespace_inheritable(:lint, true)
86+
end
87+
8488
def do_not_document!
8589
namespace_inheritable(:do_not_document, true)
8690
end

lib/grape/endpoint.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ def build_stack(helpers)
358358
format = namespace_inheritable(:format)
359359

360360
stack.use Rack::Head
361+
stack.use Rack::Lint if lint?
361362
stack.use Class.new(Grape::Middleware::Error),
362363
helpers: helpers,
363364
format: format,
@@ -408,5 +409,9 @@ def build_response_cookies
408409
Rack::Utils.set_cookie_header! header, name, cookie_value
409410
end
410411
end
412+
413+
def lint?
414+
namespace_inheritable(:lint) || Grape.config.lint
415+
end
411416
end
412417
end

spec/grape/api_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4738,4 +4738,28 @@ def uniqe_id_route
47384738
expect(last_response.body).to eq('unknown params_builder: unknown')
47394739
end
47404740
end
4741+
4742+
describe '.lint!' do
4743+
let(:app) do
4744+
Class.new(described_class) do
4745+
lint!
4746+
get '/' do
4747+
status 42
4748+
end
4749+
end
4750+
end
4751+
4752+
around do |example|
4753+
@lint = Grape.config.lint
4754+
Grape.config.lint = false
4755+
example.run
4756+
ensure
4757+
Grape.config.lint = @lint
4758+
end
4759+
4760+
it 'raises a Rack::Lint error' do
4761+
# Status must be an Integer >= 100
4762+
expect { get '/' }.to raise_error(Rack::Lint::LintError)
4763+
end
4764+
end
47414765
end

spec/integration/rails/mounting_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
context 'rails mounted' do
55
let(:api) do
66
Class.new(Grape::API) do
7+
lint!
78
get('/test_grape') { 'rails mounted' }
89
end
910
end
@@ -28,7 +29,7 @@
2829
mount GrapeApi => '/'
2930

3031
get 'up', to: lambda { |_env|
31-
['200', {}, ['hello world']]
32+
[200, {}, ['hello world']]
3233
}
3334
end
3435
end

spec/spec_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
end
1414
end
1515

16+
Grape.config.lint = true # lint all apis by default
1617
Grape::Util::Registry.include(Deregister)
1718
# issue with ruby 2.7 with ^. We need to extend it again
1819
Grape::Validations.extend(Grape::Util::Registry) if Gem::Version.new(RUBY_VERSION).release < Gem::Version.new('3.0')

0 commit comments

Comments
 (0)