Skip to content

Validates response processed by exception handler #1776

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prev Previous commit
Next Next commit
Use default_rescue_handler to handle invalid response
  • Loading branch information
darren987469 committed Aug 10, 2018
commit d2bc1b67e049c80a1f70d73f7fba3b5c13797852
11 changes: 1 addition & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2254,16 +2254,7 @@ class Twitter::API < Grape::API
end
```

By default, object returned by `rescue_from` would be taken as response message. It is suggested to call `error!` in the last line of `rescue_from` block. But you could return `String`, `Hash`, `Array`, `Rack::Response` or even `nil` as well.

```ruby
rescue_from(:all) { error!('error') }
rescue_from(:all) { 'error' }
rescue_from(:all) { { message: 'error' } }
rescue_from(:all) { [500, 'error', { 'Content-Type' => 'text/error' }] }
rescue_from(:all) { Rack::Response.new('error', 500) }
rescue_from(:all) { nil } # response default_message and default_status
```
The `rescue_from` block must return a `Rack::Response` object, or call `error!`.

The `with` keyword is available as `rescue_from` options, it can be passed method name or Proc object.

Expand Down
13 changes: 3 additions & 10 deletions lib/grape/middleware/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,18 +128,11 @@ def run_rescue_handler(handler, error)
end

response = handler.arity.zero? ? instance_exec(&handler) : instance_exec(error, &handler)
return response if response.is_a?(Rack::Response)

# take object returned from handler as [message, status, headers]
# assign default value if they are nil
message, status, headers = response
message ||= default_options[:default_message]
status ||= default_options[:default_status]

if headers.present? && headers.is_a?(Hash)
error!(message, status, headers)
if response.is_a?(Rack::Response)
response
else
error!(message, status)
run_rescue_handler(:default_rescue_handler, Grape::Exceptions::InvalidResponse.new)
end
end
end
Expand Down
52 changes: 7 additions & 45 deletions spec/grape/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1724,52 +1724,14 @@ class CustomError < Grape::Exceptions::Base; end
expect(last_response.body).to eq('Formatter Error')
end

context 'takes object returned by rescue_from as error message' do
it 'accepts nil and returns default message and status' do
subject.rescue_from(:all) { nil }
subject.get('/') { raise }
it 'uses default_rescue_handler to handle invalid response from rescue_from' do
subject.rescue_from(:all) { 'error' }
subject.get('/') { raise }

get '/'
expect(last_response.status).to eql 500
expect(last_response.body).to eql ''
end

it 'accepts string' do
subject.rescue_from(:all) { 'whatever' }
subject.get('/') { raise }

get '/'
expect(last_response.status).to eql 500
expect(last_response.body).to eql 'whatever'
end

it 'accepts hash' do
hash = { message: 'error' }
subject.rescue_from(:all) { hash }
subject.get('/') { raise }

get '/'
expect(last_response.status).to eql 500
expect(last_response.body).to eql hash.to_json
end

it 'accepts Array' do
subject.rescue_from(:all) { ['error', 400] }
subject.get('/') { raise }

get '/'
expect(last_response.status).to eql 400
expect(last_response.body).to eql 'error'
end

it 'accepts Rack::Response' do
subject.rescue_from(:all) { Rack::Response.new('error', 400) }
subject.get('/') { raise }

get '/'
expect(last_response.status).to eql 400
expect(last_response.body).to eql 'error'
end
expect_any_instance_of(Grape::Middleware::Error).to receive(:default_rescue_handler).and_call_original
get '/'
expect(last_response.status).to eql 500
expect(last_response.body).to eql 'Invalid response'
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/grape/middleware/exception_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def app
subject do
Rack::Builder.app do
use Spec::Support::EndpointFaker
use Grape::Middleware::Error, rescue_handlers: { NotImplementedError => -> { ['rescued', 200, {}] } }
use Grape::Middleware::Error, rescue_handlers: { NotImplementedError => -> { Rack::Response.new('rescued', 200, {}) } }
run ExceptionSpec::OtherExceptionApp
end
end
Expand Down