From c20aa26084b498f67b1d00ca957e86d5dbe797ae Mon Sep 17 00:00:00 2001 From: tamsin johnson Date: Wed, 24 Jan 2024 16:14:33 -0800 Subject: [PATCH] lets-go:3.4 wrapping up chapter 3 with error and config refactors --- snippetbox/cmd/web/handlers.go | 12 +++---- snippetbox/cmd/web/helpers.go | 26 ++++++++++++++ snippetbox/cmd/web/logger.go | 26 ++++++++++++++ snippetbox/cmd/web/main.go | 34 +++---------------- snippetbox/cmd/web/routes.go | 20 +++++++++++ .../ui/html/pages/{home.bak => home.tmpl} | 0 6 files changed, 81 insertions(+), 37 deletions(-) create mode 100644 snippetbox/cmd/web/helpers.go create mode 100644 snippetbox/cmd/web/logger.go create mode 100644 snippetbox/cmd/web/routes.go rename snippetbox/ui/html/pages/{home.bak => home.tmpl} (100%) diff --git a/snippetbox/cmd/web/handlers.go b/snippetbox/cmd/web/handlers.go index e44b175..ca03a6b 100644 --- a/snippetbox/cmd/web/handlers.go +++ b/snippetbox/cmd/web/handlers.go @@ -3,7 +3,6 @@ package main import ( "fmt" "html/template" - "log/slog" "net/http" "strconv" ) @@ -23,16 +22,13 @@ func (app *application) home(w http.ResponseWriter, r *http.Request) { ts, err := template.ParseFiles(files...) if err != nil { - app.logger.Error(err.Error(), slog.String("method", r.Method), slog.String("uri", r.URL.RequestURI())) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) + app.serverError(w, r, err) return } err = ts.ExecuteTemplate(w, "base", nil) if err != nil { - app.logger.Error(err.Error(), slog.String("method", r.Method), slog.String("uri", r.URL.RequestURI())) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return + app.serverError(w, r, err) } } @@ -40,7 +36,7 @@ func (app *application) home(w http.ResponseWriter, r *http.Request) { func (app *application) snippetView(w http.ResponseWriter, r *http.Request) { id, err := strconv.Atoi(r.URL.Query().Get("id")) if err != nil || id < 1 { - http.NotFound(w, r) + app.notFound(w) return } @@ -52,7 +48,7 @@ func (app *application) snippetCreate(w http.ResponseWriter, r *http.Request) { w.Header().Set("Allow", "POST") if r.Method != http.MethodPost { - http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + app.clientError(w, http.StatusMethodNotAllowed) return } diff --git a/snippetbox/cmd/web/helpers.go b/snippetbox/cmd/web/helpers.go new file mode 100644 index 0000000..d7392c6 --- /dev/null +++ b/snippetbox/cmd/web/helpers.go @@ -0,0 +1,26 @@ +package main + +import ( + "log/slog" + "net/http" + "runtime/debug" +) + +func (app *application) serverError(w http.ResponseWriter, r *http.Request, err error) { + var ( + method = r.Method + trace = string(debug.Stack()) + uri = r.URL.RequestURI() + ) + + app.logger.Error(err.Error(), slog.String("method", method), slog.String("trace", trace), slog.String("uri", uri)) + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) +} + +func (app *application) clientError(w http.ResponseWriter, status int) { + http.Error(w, http.StatusText(status), status) +} + +func (app *application) notFound(w http.ResponseWriter) { + app.clientError(w, http.StatusNotFound) +} diff --git a/snippetbox/cmd/web/logger.go b/snippetbox/cmd/web/logger.go new file mode 100644 index 0000000..f466c00 --- /dev/null +++ b/snippetbox/cmd/web/logger.go @@ -0,0 +1,26 @@ +package main + +import ( + "log/slog" + "os" +) + +// loggerBuilder ... +func loggerBuilder(logfmt *string, loglevel *string) *slog.Logger { + var logger *slog.Logger + var handler_options slog.HandlerOptions + + switch *loglevel { + case "DEBUG": handler_options = slog.HandlerOptions{Level: slog.LevelDebug} + case "INFO": handler_options = slog.HandlerOptions{Level: slog.LevelInfo} + case "WARN": handler_options = slog.HandlerOptions{Level: slog.LevelWarn} + case "ERROR": handler_options = slog.HandlerOptions{Level: slog.LevelError} + } + + switch *logfmt { + case "json": logger = slog.New(slog.NewJSONHandler(os.Stdout, &handler_options)) + default: logger = slog.New(slog.NewTextHandler(os.Stdout, &handler_options)) + } + + return logger +} diff --git a/snippetbox/cmd/web/main.go b/snippetbox/cmd/web/main.go index 6652d9f..44b065d 100644 --- a/snippetbox/cmd/web/main.go +++ b/snippetbox/cmd/web/main.go @@ -20,37 +20,13 @@ func main() { loglevel := flag.String("loglevel", "INFO", "Log level: DEBUG, INFO, WARN, or ERROR") flag.Parse() - var logger *slog.Logger - var handler_options slog.HandlerOptions - - switch *loglevel { - case "DEBUG": handler_options = slog.HandlerOptions{Level: slog.LevelDebug} - case "INFO": handler_options = slog.HandlerOptions{Level: slog.LevelInfo} - case "WARN": handler_options = slog.HandlerOptions{Level: slog.LevelWarn} - case "ERROR": handler_options = slog.HandlerOptions{Level: slog.LevelError} - } - - switch *logfmt { - case "json": logger = slog.New(slog.NewJSONHandler(os.Stdout, &handler_options)) - default: logger = slog.New(slog.NewTextHandler(os.Stdout, &handler_options)) - } - + // setup the application app := &application{ - logger: logger, + logger: loggerBuilder(logfmt, loglevel), } - mux := http.NewServeMux() - - // setup server for static files - fileServer := http.FileServer(http.Dir("./ui/static")) - mux.Handle("/static/", http.StripPrefix("/static", fileServer)) - - mux.HandleFunc("/", app.home) - mux.HandleFunc("/snippet/view", app.snippetView) - mux.HandleFunc("/snippet/create", app.snippetCreate) - - logger.Info("starting server", slog.String("addr", *addr)) - err := http.ListenAndServe(*addr, mux) - logger.Error(err.Error()) + app.logger.Info("starting server", slog.String("addr", *addr)) + err := http.ListenAndServe(*addr, app.routes()) + app.logger.Error(err.Error()) os.Exit(1) } diff --git a/snippetbox/cmd/web/routes.go b/snippetbox/cmd/web/routes.go new file mode 100644 index 0000000..9f67c0b --- /dev/null +++ b/snippetbox/cmd/web/routes.go @@ -0,0 +1,20 @@ +package main + +import ( + "net/http" +) + +// routes ... +func (app *application) routes() *http.ServeMux { + mux := http.NewServeMux() + + // setup server for static files + fileServer := http.FileServer(http.Dir("./ui/static")) + mux.Handle("/static/", http.StripPrefix("/static", fileServer)) + + mux.HandleFunc("/", app.home) + mux.HandleFunc("/snippet/view", app.snippetView) + mux.HandleFunc("/snippet/create", app.snippetCreate) + + return mux +} diff --git a/snippetbox/ui/html/pages/home.bak b/snippetbox/ui/html/pages/home.tmpl similarity index 100% rename from snippetbox/ui/html/pages/home.bak rename to snippetbox/ui/html/pages/home.tmpl