I have a simple Sinatra rest and I am having trouble trapping an error. I also admit I am fairly new to Ruby and Sinatra.
When I raise and error in the post endpoint I want to report the incoming document. I need to either 1) handle the error within the post result (where I have access to @incoming) or 2) pass the incoming document to the error and report it there.
What is a better option, option 1 or option 2?
Below is a sample of my code:
post ('/result') do
begin
@incoming = JSON.parse(request.body.read)
//do something that causes an error
rescue
e = env['sinatra.error']
url = request.url
ip = request.ip
@actlogpassblock = { :message => e.message,
:path => url,
:ip => ip,
:timestamp => Time.new,
:type => "500",
:sub => "RES",
:payload => @incoming
}
action_log.insert(@actlogpassblock)
status 500
end
end
error do
status 500
e = env['sinatra.error']
url = request.url
ip = request.ip
backtrace = "Application error\n#{e}\n#{e.backtrace.join("\n")}"
@actlogpassblock = { :message => e.message,
:path => url,
:ip => ip,
:timestamp => Time.new,
:type => "500",
:backtrace => backtrace
}
action_log.insert(@actlogpassblock)
{:result => 'Ah Shucks! Something went wrong'}.to_json
end
If I stay with option 1, how do I prevent error from picking up the error (as it seems to be doing now)
According to the docs:
The error handler is invoked any time an exception is raised from a route block...
However, that only applies to uncaught exceptions. Try this:
require 'sinatra'
set :show_exceptions, false
get '/' do
begin
raise ZeroDivisionError
rescue ZeroDivisionError
"rescue clause"
end
end
error do
"sinatra error handler"
end
Then try this:
get '/' do
raise ZeroDivisionError
end
error do
"sinatra error handler"
end
Also, you can tailor the error handler to only catch certain exceptions thereby avoiding some exceptions, e.g.
error IndexError do ...
or
error MyCustomException do ...
or
error 400..510 do
But for the catch all version:
error do
you can't stop that from executing when an uncaught exception occurs in a route block...unless:
The error handlers will only be invoked, however, if both the Sinatra :raise_errors and :show_exceptions configuration options have been set to false...
:raise_errors defaults to true in the "test" environment and to false on other environments.
:show_exceptions value defaults to true in the "development" environment and to false on other environments
The author of Sintra has said: "This [behavior] is intentional. The idea is that error blocks will hide the issue and you usually don't want to do this in development mode.
https://github.com/sul-dlss/sdr-services-app/blob/master/Sinatra-error-handling.md
If I go to option 2, how do I pass incoming to error?
An @variable that is created inside a route block can be seen inside an error block. Try this:
require 'sinatra'
set :show_exceptions, false
get '/' do
@incoming = "hello world" #create @variable
raise ZeroDivisionError
end
error ZeroDivisionError do
@incoming #retrieve @variable
end
After entering the url http://localhost:4567
in your browser, you should see "hello world" on the returned web page.
The reason that works is because an @variable attaches itself to whatever object is self at the time the @variable is created; likewise when an @variable is summoned, it is retrieved from whatever object is self at that time. When Sinatra executes either the route block or the error block it sets self to the same object.
Option 2 seems nice because it separates the error handling code from the application code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With