diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a358f996e..be7f7d55f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,9 @@ #### Fixes * [#1740](/~https://github.com/ruby-grape/grape/pull/1740): Fix dependent parameter validation using `given` when parameter is a `Hash` - [@jvortmann](/~https://github.com/jvortmann). - -* Your contribution here. * [#1737](/~https://github.com/ruby-grape/grape/pull/1737): Fix translating error when passing symbols as params in custom validations - [@mlzhuyi](/~https://github.com/mlzhuyi). +* [#1749](/~https://github.com/ruby-grape/grape/pull/1749): Allow rescue from non-`StandardError` errors - [@dm1try](/~https://github.com/dm1try). +* Your contribution here. ### 1.0.2 (1/10/2018) diff --git a/README.md b/README.md index 9e70ddd8c1..6635909eff 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ - [Exception Handling](#exception-handling) - [Rescuing exceptions inside namespaces](#rescuing-exceptions-inside-namespaces) - [Unrescuable Exceptions](#unrescuable-exceptions) + - [Exceptions that should be rescued explicitly](#exceptions-that-should-be-rescued-explicitly) - [Rails 3.x](#rails-3x) - [Logging](#logging) - [API Formats](#api-formats) @@ -2079,6 +2080,9 @@ class Twitter::API < Grape::API end ``` +This mimics [default `rescue` behaviour](https://ruby-doc.org/core/StandardError.html) when an exception type is not provided. +Any other exception should be rescued explicitly, see [below](#exceptions-that-should-be-rescued-explicitly). + Grape can also rescue from all exceptions and still use the built-in exception handing. This will give the same behavior as `rescue_from :all` with the addition that Grape will use the exception handling defined by all Exception classes that inherit `Grape::Exceptions::Base`. @@ -2281,6 +2285,12 @@ Here `'inner'` will be result of handling occured `ArgumentError`. `Grape::Exceptions::InvalidVersionHeader`, which is raised when the version in the request header doesn't match the currently evaluated version for the endpoint, will _never_ be rescued from a `rescue_from` block (even a `rescue_from :all`) This is because Grape relies on Rack to catch that error and try the next versioned-route for cases where there exist identical Grape endpoints with different versions. +#### Exceptions that should be rescued explicitly + +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) + ### Rails 3.x When mounted inside containers, such as Rails 3.x, errors such as "404 Not Found" or diff --git a/lib/grape/middleware/error.rb b/lib/grape/middleware/error.rb index 3c00786bfd..bdb0b073c7 100644 --- a/lib/grape/middleware/error.rb +++ b/lib/grape/middleware/error.rb @@ -46,6 +46,14 @@ 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 diff --git a/spec/grape/middleware/exception_spec.rb b/spec/grape/middleware/exception_spec.rb index e6bb44597b..54df280fe4 100644 --- a/spec/grape/middleware/exception_spec.rb +++ b/spec/grape/middleware/exception_spec.rb @@ -109,6 +109,19 @@ def app end 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 + end + end + it 'rescues the exception using the provided handler' do + get '/' + expect(last_response.body).to eq('rescued') + end + end context do subject do Rack::Builder.app do