Skip to content

Commit

Permalink
Fix rescue_from ValidationErrors exception (#2480)
Browse files Browse the repository at this point in the history
* Fix rescue_from ValidationErrors exception

* Update CHANGELOG
  • Loading branch information
numbata authored Jul 24, 2024
1 parent 838c75e commit 2b8567a
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

* [#2471](https://github.com/ruby-grape/grape/pull/2471): Fix absence of original_exception and/or backtrace even if passed in error! - [@numbata](https://github.com/numbata).
* [#2478](https://github.com/ruby-grape/grape/pull/2478): Fix rescue_from with invalid response - [@ericproulx](https://github.com/ericproulx).
* [#2480](https://github.com/ruby-grape/grape/pull/2480): Fix rescue_from ValidationErrors exception - [@numbata](https://github.com/numbata).
* Your contribution here.

### 2.1.3 (2024-07-13)
Expand Down
17 changes: 13 additions & 4 deletions lib/grape/error_formatter/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ class << self
def call(message, backtrace, options = {}, env = nil, original_exception = nil)
result = wrap_message(present(message, env))

rescue_options = options[:rescue_options] || {}
result = result.merge(backtrace: backtrace) if rescue_options[:backtrace] && backtrace && !backtrace.empty?
result = result.merge(original_exception: original_exception.inspect) if rescue_options[:original_exception] && original_exception
result = merge_rescue_options(result, backtrace, options, original_exception) if result.is_a?(Hash)

::Grape::Json.dump(result)
end

private

def wrap_message(message)
if message.is_a?(Exceptions::ValidationErrors) || message.is_a?(Hash)
if message.is_a?(Hash)
message
elsif message.is_a?(Exceptions::ValidationErrors)
message.as_json
else
{ error: ensure_utf8(message) }
end
Expand All @@ -30,6 +31,14 @@ def ensure_utf8(message)

message.encode('UTF-8', invalid: :replace, undef: :replace)
end

def merge_rescue_options(result, backtrace, options, original_exception)
rescue_options = options[:rescue_options] || {}
result = result.merge(backtrace: backtrace) if rescue_options[:backtrace] && backtrace && !backtrace.empty?
result = result.merge(original_exception: original_exception.inspect) if rescue_options[:original_exception] && original_exception

result
end
end
end
end
Expand Down
51 changes: 51 additions & 0 deletions spec/grape/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2743,6 +2743,57 @@ def self.call(message, _backtrace, _options, _env, _original_exception)
it { is_expected.to have_key('backtrace') & have_key('original-exception') }
end
end

context 'when rescue validation errors include backtrace and original exception' do
let(:app) do
response_type = response_format

Class.new(Grape::API) do
format response_type

rescue_from Grape::Exceptions::ValidationErrors, backtrace: true, original_exception: true do |e|
error!(e, 418, {}, e.backtrace, e)
end

params do
requires :weather
end
get '/forecast' do
'sunny'
end
end
end

before do
get '/forecast'
end

context 'with json response type format' do
subject { JSON.parse(last_response.body) }

let(:response_format) { :json }

it 'does not include backtrace or original exception' do
expect(subject).to match([{ 'messages' => ['is missing'], 'params' => ['weather'] }])
end
end

context 'with txt response type format' do
subject { last_response.body }

let(:response_format) { :txt }

it { is_expected.to include('backtrace', 'original exception') }
end

context 'with xml response type format' do
subject { Grape::Xml.parse(last_response.body)['error'] }

let(:response_format) { :xml }

it { is_expected.to have_key('backtrace') & have_key('original-exception') }
end
end
end

describe '.content_type' do
Expand Down

0 comments on commit 2b8567a

Please sign in to comment.