Skip to content

Commit 8e8fe68

Browse files
committed
Added rescue_with_backtrace true/false.
1 parent c1f2d8b commit 8e8fe68

File tree

5 files changed

+54
-15
lines changed

5 files changed

+54
-15
lines changed

README.markdown

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,11 @@ Serialization takes place automatically. For more detailed usage information, pl
6666

6767
The default behavior of Grape is to rescue all exceptions and to return a 403 status code with the exception's message in the response body.
6868

69-
It's possible to trap all exceptions by setting `rescue_all_errors true`. This prevents displaying the web server's error page as a result. You may also change the error format to JSON by using `error_format :json` and set the default error status to 200 with `default_error_status 200`.
69+
It's possible to trap all exceptions by setting `rescue_all_errors true`. This prevents displaying the web server's error page as a result. You may also change the error format to JSON by using `error_format :json` and set the default error status to 200 with `default_error_status 200`. You may also include the complete backtrace of the exception with `rescue_with_backtrace true`.
7070

7171
class Twitter::API < Grape::API
7272
rescue_all_errors true
73+
rescue_with_backtrace true
7374
error_format :json
7475
default_error_status 200
7576

lib/grape/api.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ def rescue_all_errors(new_value = true)
9595
set(:rescue_all_errors, new_value)
9696
end
9797

98+
# Specify whether to include error backtrace with errors.
99+
def rescue_with_backtrace(new_value = true)
100+
set(:rescue_with_backtrace, new_value)
101+
end
102+
98103
# Add helper methods that will be accessible from any
99104
# endpoint within this namespace (and child namespaces).
100105
#
@@ -233,7 +238,7 @@ def nest(*blocks, &block)
233238

234239
def build_endpoint(&block)
235240
b = Rack::Builder.new
236-
b.use Grape::Middleware::Error, :default_status => settings[:default_error_status] || 403, :rescue => settings[:rescue_all_errors], :format => settings[:error_format] || :txt
241+
b.use Grape::Middleware::Error, :default_status => settings[:default_error_status] || 403, :rescue => settings[:rescue_all_errors], :format => settings[:error_format] || :txt, :backtrace => settings[:rescue_with_backtrace]
237242
b.use Rack::Auth::Basic, settings[:auth][:realm], &settings[:auth][:proc] if settings[:auth] && settings[:auth][:type] == :http_basic
238243
b.use Grape::Middleware::Prefixer, :prefix => prefix if prefix
239244
b.use Grape::Middleware::Versioner, :versions => (version if version.is_a?(Array)) if version

lib/grape/middleware/error.rb

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ def default_options
1111
:default_message => "",
1212
:format => :txt,
1313
:formatters => {},
14+
:backtrace => false, # true to display backtrace
1415
}
1516
end
1617

@@ -35,12 +36,21 @@ def formatter_for(api_format)
3536
end
3637
end
3738

38-
def format_json(message)
39-
{ :error => message }.to_json
39+
def format_json(message, backtrace)
40+
result = { :error => message }
41+
if (options[:backtrace] && backtrace && ! backtrace.empty?)
42+
result = result.merge({ :backtrace => backtrace })
43+
end
44+
result.to_json
4045
end
4146

42-
def format_txt(message)
43-
message
47+
def format_txt(message, backtrace)
48+
result = message
49+
if options[:backtrace] && backtrace && ! backtrace.empty?
50+
result += "\r\n "
51+
result += backtrace.join("\r\n ")
52+
end
53+
result
4454
end
4555

4656
def call!(env)
@@ -52,7 +62,7 @@ def call!(env)
5262
})
5363
rescue Exception => e
5464
raise unless options[:rescue]
55-
error_response({ :message => e.message })
65+
error_response({ :message => e.message, :backtrace => e.backtrace })
5666
end
5767

5868
end
@@ -61,13 +71,14 @@ def error_response(error = {})
6171
status = error[:status] || options[:default_status]
6272
message = error[:message] || options[:default_message]
6373
headers = error[:headers] || {}
64-
Rack::Response.new([format_message(message, status)], status, headers).finish
74+
backtrace = error[:backtrace] || []
75+
Rack::Response.new([format_message(message, backtrace, status)], status, headers).finish
6576
end
6677

67-
def format_message(message, status)
78+
def format_message(message, backtrace, status)
6879
formatter = formatter_for(options[:format])
6980
throw :error, :status => 406, :message => "The requested format #{options[:format]} is not supported." unless formatter
70-
formatter.call(message)
81+
formatter.call(message, backtrace)
7182
end
7283

7384
end

spec/grape/api_spec.rb

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ def two
491491
end
492492

493493
describe ".error_format" do
494-
it 'should return :txt' do
494+
it 'should rescue all errors and return :txt' do
495495
subject.rescue_all_errors true
496496
subject.error_format :txt
497497
subject.get '/exception' do
@@ -500,7 +500,17 @@ def two
500500
get '/exception'
501501
last_response.body.should eql "rain!"
502502
end
503-
it 'should rescue all errors' do
503+
it 'should rescue all errros and return :txt with backtrace' do
504+
subject.rescue_all_errors true
505+
subject.error_format :txt
506+
subject.rescue_with_backtrace true
507+
subject.get '/exception' do
508+
raise "rain!"
509+
end
510+
get '/exception'
511+
last_response.body.start_with?("rain!\r\n").should be_true
512+
end
513+
it 'should rescue all errors and return :json' do
504514
subject.rescue_all_errors true
505515
subject.error_format :json
506516
subject.get '/exception' do
@@ -509,15 +519,27 @@ def two
509519
get '/exception'
510520
last_response.body.should eql '{"error":"rain!"}'
511521
end
512-
it 'should rescue all errors' do
522+
it 'should rescue all errors and return :json with backtrace' do
523+
subject.rescue_all_errors true
524+
subject.error_format :json
525+
subject.rescue_with_backtrace true
526+
subject.get '/exception' do
527+
raise "rain!"
528+
end
529+
get '/exception'
530+
json = JSON.parse(last_response.body)
531+
json["error"].should eql 'rain!'
532+
json["backtrace"].length.should > 0
533+
end
534+
it 'should rescue error! and return txt' do
513535
subject.error_format :txt
514536
subject.get '/error' do
515537
error!("Access Denied", 401)
516538
end
517539
get '/error'
518540
last_response.body.should eql "Access Denied"
519541
end
520-
it 'should rescue all errors' do
542+
it 'should rescue error! and return json' do
521543
subject.error_format :json
522544
subject.get '/error' do
523545
error!("Access Denied", 401)

spec/grape/middleware/exception_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def app
7373
use Grape::Middleware::Error,
7474
:format => :custom,
7575
:formatters => {
76-
:custom => lambda { |message| { :custom_formatter => message } }
76+
:custom => lambda { |message, backtrace| { :custom_formatter => message } }
7777
}
7878
run ExceptionApp
7979
end

0 commit comments

Comments
 (0)