Start implementing error block
This commit is contained in:
parent
35239dfaa0
commit
e6d9311895
7 changed files with 71 additions and 25 deletions
|
@ -2,10 +2,27 @@ require "./spec_helper"
|
|||
|
||||
describe "Kemal::CommonExceptionHandler" do
|
||||
it "renders 404 on route not found" do
|
||||
common_exception_handler = Kemal::CommonExceptionHandler::INSTANCE
|
||||
request = HTTP::Request.new("GET", "/?message=world")
|
||||
io_with_context = create_request_and_return_io(common_exception_handler, request)
|
||||
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||
get "/" do |env|
|
||||
"Hello"
|
||||
end
|
||||
|
||||
request = HTTP::Request.new("GET", "/asd")
|
||||
client_response = call_request_on_app(request)
|
||||
client_response.status_code.should eq 404
|
||||
end
|
||||
|
||||
it "renders custom error" do
|
||||
error 403 do
|
||||
"403 error"
|
||||
end
|
||||
|
||||
get "/" do |env|
|
||||
env.response.status_code = 403
|
||||
end
|
||||
|
||||
request = HTTP::Request.new("GET", "/")
|
||||
client_response = call_request_on_app(request)
|
||||
client_response.status_code.should eq 403
|
||||
client_response.body.should eq "403 error"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,6 @@ require "./kemal/*"
|
|||
require "./kemal/middleware/*"
|
||||
|
||||
module Kemal
|
||||
|
||||
# The command to run a `Kemal` application.
|
||||
def self.run
|
||||
Kemal::CLI.new
|
||||
|
@ -13,6 +12,10 @@ module Kemal
|
|||
config.server = HTTP::Server.new(config.host_binding.not_nil!, config.port, config.handlers)
|
||||
config.server.not_nil!.ssl = config.ssl
|
||||
|
||||
error 404 do |env|
|
||||
render_404(env)
|
||||
end
|
||||
|
||||
# Test environment doesn't need to have signal trap, built-in images, and logging.
|
||||
unless config.env == "test"
|
||||
Signal::INT.trap {
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
class Kemal::CommonExceptionHandler < HTTP::Handler
|
||||
INSTANCE = new
|
||||
module Kemal
|
||||
class CommonExceptionHandler < HTTP::Handler
|
||||
INSTANCE = new
|
||||
|
||||
def call(context)
|
||||
begin
|
||||
call_next context
|
||||
rescue ex : Kemal::Exceptions::RouteNotFound
|
||||
context.response.content_type = "text/html"
|
||||
Kemal.config.logger.write("Exception: #{ex.inspect_with_backtrace}\n")
|
||||
return render_404(context)
|
||||
rescue ex
|
||||
context.response.content_type = "text/html"
|
||||
Kemal.config.logger.write("Exception: #{ex.inspect_with_backtrace}\n")
|
||||
verbosity = Kemal.config.env == "production" ? false : true
|
||||
return render_500(context, ex.inspect_with_backtrace, verbosity)
|
||||
def call(context)
|
||||
begin
|
||||
call_next(context)
|
||||
rescue ex : Kemal::Exceptions::RouteNotFound
|
||||
return Kemal.config.error_handlers[404].call(context)
|
||||
rescue ex1 : Kemal::Exceptions::CustomException
|
||||
status_code = ex1.context.response.status_code
|
||||
return Kemal.config.error_handlers[status_code].call(context) if Kemal.config.error_handlers.key?(status_code)
|
||||
rescue ex2
|
||||
Kemal.config.error_handlers[500].call(context) if Kemal.config.error_handlers.key?(500)
|
||||
context.response.content_type = "text/html"
|
||||
Kemal.config.logger.write("Exception: #{ex2.inspect_with_backtrace}\n")
|
||||
verbosity = Kemal.config.env == "production" ? false : true
|
||||
return render_500(context, ex2.inspect_with_backtrace, verbosity)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
module Kemal
|
||||
class Config
|
||||
INSTANCE = Config.new
|
||||
HANDLERS = [] of HTTP::Handler
|
||||
INSTANCE = Config.new
|
||||
HANDLERS = [] of HTTP::Handler
|
||||
ERROR_HANDLERS = {} of Int32 => HTTP::Server::Context -> String
|
||||
@ssl : OpenSSL::SSL::Context?
|
||||
@server : HTTP::Server?
|
||||
|
||||
property host_binding, ssl, port, env, public_folder, logging,
|
||||
always_rescue, serve_static, server
|
||||
always_rescue, serve_static, server, error_handler
|
||||
|
||||
def initialize
|
||||
@host_binding = "0.0.0.0"
|
||||
|
@ -19,8 +20,6 @@ module Kemal
|
|||
@error_handler = nil
|
||||
@always_rescue = true
|
||||
@run = false
|
||||
@ssl = nil
|
||||
@server = nil
|
||||
end
|
||||
|
||||
def logger
|
||||
|
@ -47,6 +46,14 @@ module Kemal
|
|||
HANDLERS << handler
|
||||
end
|
||||
|
||||
def error_handlers
|
||||
ERROR_HANDLERS
|
||||
end
|
||||
|
||||
def add_error_handler(status_code, &handler : HTTP::Server::Context -> _)
|
||||
ERROR_HANDLERS[status_code] = ->(context : HTTP::Server::Context) { handler.call(context).to_s }
|
||||
end
|
||||
|
||||
def setup
|
||||
setup_log_handler
|
||||
setup_error_handler
|
||||
|
|
|
@ -9,3 +9,7 @@ HTTP_METHODS = %w(get post put patch delete options)
|
|||
def ws(path, &block : HTTP::WebSocket, HTTP::Server::Context -> Void)
|
||||
Kemal::WebSocketHandler.new path, &block
|
||||
end
|
||||
|
||||
def error(status_code, &block : HTTP::Server::Context -> _)
|
||||
Kemal.config.add_error_handler status_code, &block
|
||||
end
|
||||
|
|
|
@ -4,4 +4,12 @@ module Kemal::Exceptions
|
|||
super "Requested path: '#{context.request.override_method as String}:#{context.request.path}' was not found."
|
||||
end
|
||||
end
|
||||
|
||||
class CustomException < Exception
|
||||
getter context
|
||||
|
||||
def initialize(@context)
|
||||
super "Rendered error with #{@context.response.status_code}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,9 +31,12 @@ class Kemal::RouteHandler < HTTP::Handler
|
|||
|
||||
# Processes the route if it's a match. Otherwise renders 404.
|
||||
def process_request(context)
|
||||
raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_defined?
|
||||
return raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_defined?
|
||||
route = context.route_lookup.payload as Route
|
||||
context.response.print(route.handler.call(context))
|
||||
if Kemal.config.error_handlers.has_key?(context.response.status_code)
|
||||
return raise Kemal::Exceptions::CustomException.new(context)
|
||||
end
|
||||
context
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue