Skip to content

Commit

Permalink
allow rescue from non-StandardError exceptions to use default error…
Browse files Browse the repository at this point in the history
… handling
  • Loading branch information
Jelkster committed Mar 27, 2018
1 parent 5613186 commit e2e6bd9
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* [#1749](https://github.com/ruby-grape/grape/pull/1749): Allow rescue from non-`StandardError` exceptions - [@dm1try](https://github.com/dm1try).
* [#1750](https://github.com/ruby-grape/grape/pull/1750): Fix a circular dependency warning due to router being loaded by API - [@salasrod](https://github.com/salasrod).
* [#1752](https://github.com/ruby-grape/grape/pull/1752): Fix `include_missing` behavior for aliased parameters - [@jonasoberschweiber](https://github.com/jonasoberschweiber).
* [#1754](https://github.com/ruby-grape/grape/pull/1754): Allow rescue from non-`StandardError` exceptions to use default error handling - [@jelkster](https://github.com/jelkster).
* Your contribution here.

### 1.0.2 (1/10/2018)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2289,7 +2289,7 @@ Here `'inner'` will be result of handling occured `ArgumentError`.

Any exception that is not subclass of `StandardError` should be rescued explicitly.
Usually it is not a case for an application logic as such errors point to problems in Ruby runtime.
This is following [standard recomendations for exceptions handling](https://ruby-doc.org/core/Exception.html).
This is following [standard recommendations for exceptions handling](https://ruby-doc.org/core/Exception.html).

### Rails 3.x

Expand Down
17 changes: 7 additions & 10 deletions lib/grape/middleware/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def call!(env)
error_response(catch(:error) do
return @app.call(@env)
end)
rescue StandardError => e
rescue Exception => e # rubocop:disable Lint/RescueException
is_rescuable = rescuable?(e.class)
if e.is_a?(Grape::Exceptions::Base) && (!is_rescuable || rescuable_by_grape?(e.class))
handler = ->(arg) { error_response(arg) }
Expand All @@ -46,14 +46,6 @@ def call!(env)
end

handler.nil? ? handle_error(e) : exec_handler(e, &handler)
rescue Exception => e # rubocop:disable Lint/RescueException
handler = options[:rescue_handlers].find do |error_class, error_handler|
break error_handler if e.class <= error_class
end

raise unless handler

exec_handler(e, &handler)
end
end

Expand All @@ -72,7 +64,12 @@ def find_handler(klass)

def rescuable?(klass)
return false if klass == Grape::Exceptions::InvalidVersionHeader
rescue_all? || rescue_class_or_its_ancestor?(klass) || rescue_with_base_only_handler?(klass)

if klass <= StandardError
rescue_all? || rescue_class_or_its_ancestor?(klass) || rescue_with_base_only_handler?(klass)
else
rescue_class_or_its_ancestor?(klass) || rescue_with_base_only_handler?(klass)
end
end

def rescuable_by_grape?(klass)
Expand Down
33 changes: 25 additions & 8 deletions spec/grape/middleware/exception_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,35 @@ def app
end

context 'Non-StandardError exception with a provided rescue handler' do
subject do
Rack::Builder.app do
use Spec::Support::EndpointFaker
use Grape::Middleware::Error, rescue_handlers: { NotImplementedError => -> { [200, {}, 'rescued'] } }
run ExceptionSpec::OtherExceptionApp
context 'default error response' do
subject do
Rack::Builder.app do
use Spec::Support::EndpointFaker
use Grape::Middleware::Error, rescue_handlers: { NotImplementedError => nil }
run ExceptionSpec::OtherExceptionApp
end
end
it 'rescues the exception using the default handler' do
get '/'
expect(last_response.body).to eq('snow!')
end
end
it 'rescues the exception using the provided handler' do
get '/'
expect(last_response.body).to eq('rescued')

context 'custom error response' do
subject do
Rack::Builder.app do
use Spec::Support::EndpointFaker
use Grape::Middleware::Error, rescue_handlers: { NotImplementedError => -> { [200, {}, 'rescued'] } }
run ExceptionSpec::OtherExceptionApp
end
end
it 'rescues the exception using the provided handler' do
get '/'
expect(last_response.body).to eq('rescued')
end
end
end

context do
subject do
Rack::Builder.app do
Expand Down

0 comments on commit e2e6bd9

Please sign in to comment.