Module: Strelka::App::Errors

Extended by:
Plugin
Includes:
Constants
Defined in:
lib/strelka/app/errors.rb

Overview

Custom error-handling plugin for Strelka::App.

plugin :errors

# Handle only status 400 errors
on_status HTTP::BAD_REQUEST do |res, status_info|
  # Do something on 400 errors
end

# Handle any other error in the 4xx range
on_status 400..499 do |res, status_info|
  # Do something on 4xx errors
end

If you have the :templating plugin loaded, you can substitute a Symbol that corresponds with one of the declared templates instead:

class MyApp < Strelka::App
  plugins :errors, :templating

  layout 'layout.tmpl'
  templates :missing => 'errors/missing.tmpl'

  # Load the 'missing' template, wrap it up in the layout
  # template and render that as the body of the 404
  # response
  on_status HTTP::NOT_FOUND, :missing

end # class MyApp

The template can access the status info hash via the :status_info note on the request or response object:

Sorry, there was a error:

<?escape request.notes[:status_info][:message] ?>.

If you want to do something application-specific for an error, but still use the default error-handling, just call finish_with again with the status info from your status handler:

class MyApp < Strelka::App
   plugins :errors

   # Send an email when an app is going to return a 500 error
   on_status HTTP::SERVER_ERROR do |res, info|
       require 'mail'
       Mail.deliver do
           from    '[email protected]'
           to      '[email protected]'
           subject "SERVER_ERROR: %p [%s]" %
                   [ self.class, self.class.version_string ]
           body    "Server error while running %p [%s]: %s" %
                   [ self.class, self.conn, status.message ]
       end

       # Finish the transaction
       finish_with( info )
   end

   def handle( req )
       finish_with( HTTP::SERVER_ERROR, "Ack! Something bad happened." )
   end

end # class MyApp

See the documentation for ClassMethods.on_status for more details on the status-handler block.

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

DEFAULT_HANDLER_STATUS_RANGE =

The range of status codes to delegate to an on_status handler that doesn't specify one

400..599

Instance Attribute Summary

Attributes included from Plugin

#pluggable, #successors

Instance Method Summary collapse

Methods included from Plugin

extended, plugin_name, run_inside, run_outside

Instance Method Details

#handle_request(request) ⇒ Object

Check for a status response that is hooked, and run the hook if one is found.



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/strelka/app/errors.rb', line 144

def handle_request( request )
	self.log.debug "[:errors] Wrapping request in custom error-handling."
	response = nil

	# Catch a finish_with; the status_response will only be non-nil
	status_response = catch( :finish ) do

		# Provide our own exception-handling and translate them into server errors
		begin
			response = super
		rescue => err
			self.log.error "%s: %s %s" % [ err.class.name, err.message, err.backtrace.first ]
			err.backtrace[ 1..-1 ].each {|frame| self.log.debug('  ' + frame) }

			finish_with(
				status:    HTTP::SERVER_ERROR,
				message:   err.message,
				headers:   {},
				backtrace: err.backtrace,
				exception: err
			)
		end
		nil
	end

	# If the app or any plugins threw a finish, look for a handler for the status code
	# and call it if one is found.
	response = self.handle_status_response( request, status_response ) if status_response

	return response
end

#handle_status_response(request, status_info) ⇒ Object

Return a response built out of the status_info for the specified request if there is a custom handler. If there isn't one, rethrows to the main :finish handler.



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/strelka/app/errors.rb', line 179

def handle_status_response( request, status_info )
	status = status_info[:status]

	# If we can't find a custom handler for this status, re-throw
	# to the default handler instead
	handler = self.status_handler_for( status ) or
		throw( :finish, status_info )
	self.log.debug "Custom %d handler: %p" % [ status, handler ]

	# Set up the request's response with the right status code
	request.notes[:status_info] = status_info
	response = request.response
	response.status = status

	# The handler is an UnboundMethod, so bind it to the app instance
	# and call it
	return handler.bind( self ).call( response, status_info )
end

#status_handler_for(status_code) ⇒ Object

Find a status handler for the given status_code and return it as an UnboundMethod.



200
201
202
203
204
205
206
207
208
209
210
# File 'lib/strelka/app/errors.rb', line 200

def status_handler_for( status_code )
	self.log.debug "[:errors] Looking for a status handler for %d responses" % [ status_code ]
	handlers = self.class.status_handlers
	ranges = handlers.keys

	ranges.each do |range|
		return handlers[ range ] if range.include?( status_code )
	end

	return nil
end