Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/jsonapi/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Configuration
:top_level_meta_page_count_key,
:allow_transactions,
:include_backtraces_in_errors,
:include_application_backtraces_in_errors,
:exception_class_whitelist,
:whitelist_all_exceptions,
:always_include_to_one_linkage_data,
Expand Down Expand Up @@ -80,6 +81,10 @@ def initialize
# responses. Defaults to `false` in production, and `true` otherwise.
self.include_backtraces_in_errors = !Rails.env.production?

# Whether or not to include exception application backtraces in JSONAPI error
# responses. Defaults to `false` in production, and `true` otherwise.
self.include_application_backtraces_in_errors = !Rails.env.production?

# List of classes that should not be rescued by the operations processor.
# For example, if you use Pundit for authorization, you might
# raise a Pundit::NotAuthorizedError at some point during operations
Expand Down Expand Up @@ -246,6 +251,8 @@ def resource_finder=(resource_finder)

attr_writer :include_backtraces_in_errors

attr_writer :include_application_backtraces_in_errors

attr_writer :exception_class_whitelist

attr_writer :whitelist_all_exceptions
Expand Down
6 changes: 6 additions & 0 deletions lib/jsonapi/exceptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ def errors
meta[:backtrace] = exception.backtrace
end

if JSONAPI.configuration.include_application_backtraces_in_errors
meta ||= Hash.new
meta[:exception] ||= exception.message
meta[:application_backtrace] = exception.backtrace.select{|line| line =~ /#{Rails.root}/}
end

[create_error_object(code: JSONAPI::INTERNAL_SERVER_ERROR,
status: :internal_server_error,
title: I18n.t('jsonapi-resources.exceptions.internal_server_error.title',
Expand Down
23 changes: 21 additions & 2 deletions test/controllers/controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,18 +126,37 @@ def test_exception_includes_backtrace_when_enabled
JSONAPI.configuration.include_backtraces_in_errors = true
assert_cacheable_get :index
assert_response 500
assert_includes @response.body, "backtrace", "expected backtrace in error body"
assert_includes @response.body, '"backtrace"', "expected backtrace in error body"

JSONAPI.configuration.include_backtraces_in_errors = false
assert_cacheable_get :index
assert_response 500
refute_includes @response.body, "backtrace", "expected backtrace in error body"
refute_includes @response.body, '"backtrace"', "expected backtrace in error body"

ensure
$PostProcessorRaisesErrors = false
JSONAPI.configuration.include_backtraces_in_errors = original_config
end

def test_exception_includes_application_backtrace_when_enabled
original_config = JSONAPI.configuration.include_application_backtraces_in_errors
$PostProcessorRaisesErrors = true

JSONAPI.configuration.include_application_backtraces_in_errors = true
assert_cacheable_get :index
assert_response 500
assert_includes @response.body, '"application_backtrace"', "expected application backtrace in error body"

JSONAPI.configuration.include_application_backtraces_in_errors = false
assert_cacheable_get :index
assert_response 500
refute_includes @response.body, '"application_backtrace"', "expected application backtrace in error body"

ensure
$PostProcessorRaisesErrors = false
JSONAPI.configuration.include_application_backtraces_in_errors = original_config
end

def test_on_server_error_block_callback_with_exception
original_config = JSONAPI.configuration.dup
JSONAPI.configuration.exception_class_whitelist = []
Expand Down
7 changes: 4 additions & 3 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ def assert_cacheable_get(action, *args)
ActiveSupport::Notifications.subscribed(normal_query_callback, 'sql.active_record') do
get action, *args
end
non_caching_response = json_response_sans_backtraces
non_caching_response = json_response_sans_all_backtraces
non_caching_status = response.status

# Don't let all the cache-testing requests mess with assert_query_count
Expand Down Expand Up @@ -565,7 +565,7 @@ def assert_cacheable_get(action, *args)
)
assert_equal(
non_caching_response.pretty_inspect,
json_response_sans_backtraces.pretty_inspect,
json_response_sans_all_backtraces.pretty_inspect,
"Cache (mode: #{mode}) #{phase} response body must match normal response"
)
assert_operator(
Expand Down Expand Up @@ -605,12 +605,13 @@ def assert_cacheable_get(action, *args)

private

def json_response_sans_backtraces
def json_response_sans_all_backtraces
return nil if response.body.to_s.strip.empty?

r = json_response.dup
(r["errors"] || []).each do |err|
err["meta"].delete("backtrace") if err.has_key?("meta")
err["meta"].delete("application_backtrace") if err.has_key?("meta")
end
return r
end
Expand Down