From cf94d41d9bca59d0c2fd3fb0eb99dcb69ba3281d Mon Sep 17 00:00:00 2001 From: Victor Vrantchan Date: Sat, 25 Jul 2020 20:28:46 -0400 Subject: [PATCH] Add validation error handling to framework --- pkg/frontend/frontend.go | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/pkg/frontend/frontend.go b/pkg/frontend/frontend.go index bbe5fc5d..0405a017 100644 --- a/pkg/frontend/frontend.go +++ b/pkg/frontend/frontend.go @@ -134,9 +134,31 @@ func (srv *Server) HandleFunc(path string, f func(http.ResponseWriter, *http.Req srv.r.HandleFunc(path, f).Methods(methods...) } -// Fail renders the 500 InternalServerError template and logs accordingly. +// Fail renders an error template. The default behavior is to render 500.tmpl with +// an http.StatusInternalServerError status code. Fail also checks for application specific failures +// like form validation. +// The first keyvals value could be the name of a template to use instead of 500.tmpl. func (srv *Server) Fail(ctx context.Context, w http.ResponseWriter, err error, keyvals ...interface{}) { - srv.RenderTemplate(ctx, w, "500.tmpl", Data{}. + tpl := "500.tmpl" + if len(keyvals) > 0 && strings.HasSuffix(keyvals[0].(string), ".tmpl") { + tpl, keyvals = keyvals[0].(string), keyvals[1:] + } + + var validationErr interface { + error + Invalid() map[string]string + } + + if errors.As(err, &validationErr) { + srv.RenderTemplate(ctx, w, tpl, Data{}. + FormErrors(validationErr.Invalid()). + WithLog(err, keyvals...). + WithCode(http.StatusBadRequest), + ) + return + } + + srv.RenderTemplate(ctx, w, tpl, Data{}. WithLog(err, keyvals...). WithCode(http.StatusInternalServerError), ) @@ -158,11 +180,13 @@ func (srv *Server) RenderTemplate(ctx context.Context, w http.ResponseWriter, na } // log the template name, avoiding loops to srv.Fail + lvl := log.Info if name != "500.tmpl" { kv = append(kv, "template", name) + lvl = log.Debug } - log.Info(logger).Log(kv...) + lvl(logger).Log(kv...) } tmpl, ok := srv.templates[name] @@ -235,7 +259,6 @@ func (srv *Server) recoverPanic(next http.Handler) http.Handler { next.ServeHTTP(w, r) }) } - func csrfDisabled(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { logger := log.FromContext(r.Context())