Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What are various options for error handling in Sinatra? #8

Open
ericgj opened this issue Jun 5, 2012 · 1 comment
Open

What are various options for error handling in Sinatra? #8

ericgj opened this issue Jun 5, 2012 · 1 comment

Comments

@ericgj
Copy link
Member

ericgj commented Jun 5, 2012

@codereading/readers

@ericgj
Copy link
Member Author

ericgj commented Jun 12, 2012

This is a somewhat complex topic, to begin with there is a distinction between

  1. You have an error condition that you want to trap and return an http error code and response for, within your app, and
  2. Your code raises an error that you don't handle, how do you want Sinatra to handle it and/or how is it handled back down the stack ?

The app-level error handling (1) is well-documented here.
Here's the method for defining an error handler:

      # Define a custom error handler. Optionally takes either an Exception
      # class, or an HTTP status code to specify which errors should be
      # handled.
      def error(*codes, &block)
        args  = compile! "ERROR", //, block
        codes = codes.map { |c| Array(c) }.flatten
        codes << Exception if codes.empty?
        codes.each { |c| @errors[c] = args }
      end

It's interesting that error handlers are defined as a special kind of route. Anyone want to take a stab at exegesis ?


As for framework-level error handling (2), the relevant code is here (called from the rescue Exception in dispatch!):

    # Error handling during requests.
    def handle_exception!(boom)
      @env['sinatra.error'] = boom
      status boom.respond_to?(:code) ? Integer(boom.code) : 500

      if server_error?
        dump_errors! boom if settings.dump_errors?
        raise boom if settings.show_exceptions? and settings.show_exceptions != :after_handler
      end

      if not_found?
        headers['X-Cascade'] = 'pass'
        body '<h1>Not Found</h1>'
      end

      res = error_block!(boom.class, boom) || error_block!(status, boom)
      return res if res or not server_error?
      raise boom if settings.raise_errors? or settings.show_exceptions?
      error_block! Exception, boom
    end

    # Find an custom error block for the key(s) specified.
    def error_block!(key, *block_params)
      base = settings
      while base.respond_to?(:errors)
        next base = base.superclass unless args = base.errors[key]
        args += [block_params]
        return process_route(*args)
      end
      return false unless key.respond_to? :superclass and key.superclass < Exception
      error_block!(key.superclass, *block_params)
    end

    def dump_errors!(boom)
      msg = ["#{boom.class} - #{boom.message}:", *boom.backtrace].join("\n\t")
      @env['rack.errors'].puts(msg)
    end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant