From 37404b48210e9ef5c08d3488aad02eb416ec28ab Mon Sep 17 00:00:00 2001 From: Drew Bednar Date: Sun, 23 Feb 2025 12:32:17 -0500 Subject: [PATCH] Refactored application creation --- cmd/ratchetd/main.go | 2 +- cmd/ratchetd/main_test.go | 2 +- internal/server/routes.go | 59 ++++++++++++++++++++++----------------- internal/server/server.go | 20 ------------- 4 files changed, 36 insertions(+), 47 deletions(-) diff --git a/cmd/ratchetd/main.go b/cmd/ratchetd/main.go index d54a646..f36483c 100644 --- a/cmd/ratchetd/main.go +++ b/cmd/ratchetd/main.go @@ -95,7 +95,7 @@ func main() { srv := &http.Server{ Addr: fmt.Sprintf("%s:%s", *addr, *port), - Handler: app, + Handler: app.Routes(), ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError), TLSConfig: &tlsConfig, // Server wide timeouts. diff --git a/cmd/ratchetd/main_test.go b/cmd/ratchetd/main_test.go index 2210a80..d8907a3 100644 --- a/cmd/ratchetd/main_test.go +++ b/cmd/ratchetd/main_test.go @@ -49,7 +49,7 @@ func TestPingIntegration(t *testing.T) { t.Parallel() app := newTestApplication(t) - ts := newTestServer(t, app) + ts := newTestServer(t, app.Routes()) defer ts.Close() code, _, body := ts.get(t, "/ping") diff --git a/internal/server/routes.go b/internal/server/routes.go index 50a0680..ec1c8ba 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -1,45 +1,54 @@ package server import ( - "database/sql" - "log/slog" "net/http" - "git.runcible.io/learning/ratchet/internal/model" - "github.com/alexedwards/scs/v2" - "github.com/go-playground/form/v4" + "git.runcible.io/learning/ratchet/ui" ) -func addRoutes(mux *http.ServeMux, - logger *slog.Logger, - tc *TemplateCache, - db *sql.DB, - fd *form.Decoder, - sm *scs.SessionManager, - userService *model.UserService, - snippetService *model.SnippetService) http.Handler { +func addBaseMiddleware(app *RatchetApp, next http.Handler, requireAuth bool) http.Handler { + var h http.Handler + if requireAuth { + h = RequireAuthenticationMiddleware(next, app.sessionManager) + } + h = AuthenticateMiddleware(next, app.sessionManager, app.userService) + h = NoSurfMiddleware(h) + h = app.sessionManager.LoadAndSave(h) + return h +} + +func (a *RatchetApp) Routes() http.Handler { + + // TODO implement middleware that disables directory listings + // This line was superceded by using the embedded filesystem + // fileServer := http.FileServer(http.Dir("./ui/static/")) + router := http.NewServeMux() - mux.Handle("GET /ping", PingHandler()) + // Subtree pattern for static assets + // This line was superceded by using the embedded filesystem + // router.Handle("GET /static/", http.StripPrefix("/static/", fileServer)) + router.Handle("GET /static/", http.FileServerFS(ui.Files)) + + router.Handle("GET /ping", PingHandler()) // /{$} is used to prevent subtree path patterns from acting like a wildcard // resulting in this route requiring an exact match on "/" only // You can only include one HTTP method in a route pattern if you choose // GET will match GET & HEAD http request methods - mux.Handle("GET /{$}", sm.LoadAndSave(NoSurfMiddleware(AuthenticateMiddleware(handleHome(logger, tc, sm, snippetService), sm, userService)))) // might be time to swith to github.com/justinas/alice dynamic chain - mux.Handle("GET /snippet/view/{id}", sm.LoadAndSave(NoSurfMiddleware(AuthenticateMiddleware(handleSnippetView(logger, tc, sm, snippetService), sm, userService)))) - mux.Handle("GET /snippet/create", sm.LoadAndSave(NoSurfMiddleware(AuthenticateMiddleware(RequireAuthenticationMiddleware(handleSnippetCreateGet(tc, sm), sm), sm, userService)))) - mux.Handle("POST /snippet/create", sm.LoadAndSave(NoSurfMiddleware(AuthenticateMiddleware(RequireAuthenticationMiddleware(handleSnippetCreatePost(logger, tc, fd, sm, snippetService), sm), sm, userService)))) + router.Handle("GET /{$}", addBaseMiddleware(a, handleHome(a.logger, a.templateCache, a.sessionManager, a.snippetService), false)) // might be time to swith to github.com/justinas/alice dynamic chain + router.Handle("GET /snippet/view/{id}", addBaseMiddleware(a, handleSnippetView(a.logger, a.templateCache, a.sessionManager, a.snippetService), false)) + router.Handle("GET /snippet/create", addBaseMiddleware(a, handleSnippetCreateGet(a.templateCache, a.sessionManager), true)) + router.Handle("POST /snippet/create", addBaseMiddleware(a, handleSnippetCreatePost(a.logger, a.templateCache, a.formDecoder, a.sessionManager, a.snippetService), true)) // mux.Handle("/something", handleSomething(logger, config)) // mux.Handle("/healthz", handleHealthzPlease(logger)) // mux.Handle("/", http.NotFoundHandler()) - mux.Handle("GET /user/signup", sm.LoadAndSave(NoSurfMiddleware(AuthenticateMiddleware(handleUserSignupGet(tc, sm), sm, userService)))) - mux.Handle("POST /user/signup", sm.LoadAndSave(NoSurfMiddleware(AuthenticateMiddleware(handleUserSignupPost(logger, tc, fd, sm, userService), sm, userService)))) - mux.Handle("GET /user/login", sm.LoadAndSave(NoSurfMiddleware(AuthenticateMiddleware(handleUserLoginGet(tc, sm), sm, userService)))) - mux.Handle("POST /user/login", sm.LoadAndSave(NoSurfMiddleware(AuthenticateMiddleware(handleUserLoginPost(logger, tc, sm, fd, userService), sm, userService)))) + router.Handle("GET /user/signup", addBaseMiddleware(a, handleUserSignupGet(a.templateCache, a.sessionManager), false)) + router.Handle("POST /user/signup", addBaseMiddleware(a, handleUserSignupPost(a.logger, a.templateCache, a.formDecoder, a.sessionManager, a.userService), false)) + router.Handle("GET /user/login", addBaseMiddleware(a, handleUserLoginGet(a.templateCache, a.sessionManager), false)) + router.Handle("POST /user/login", addBaseMiddleware(a, handleUserLoginPost(a.logger, a.templateCache, a.sessionManager, a.formDecoder, a.userService), false)) // Requires auth - mux.Handle("POST /user/logout", sm.LoadAndSave(NoSurfMiddleware(AuthenticateMiddleware(RequireAuthenticationMiddleware(handleUserLogoutPost(logger, sm), sm), sm, userService)))) - - return mux + router.Handle("POST /user/logout", addBaseMiddleware(a, handleUserLogoutPost(a.logger, a.sessionManager), true)) + return RecoveryMiddleware(RequestLoggingMiddleware(CommonHeaderMiddleware(router), a.logger)) } diff --git a/internal/server/server.go b/internal/server/server.go index bf78ad8..2e5cb2f 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -3,17 +3,13 @@ package server import ( "database/sql" "log/slog" - "net/http" "git.runcible.io/learning/ratchet/internal/model" - "git.runcible.io/learning/ratchet/ui" "github.com/alexedwards/scs/v2" "github.com/go-playground/form/v4" ) type RatchetApp struct { - http.Handler - logger *slog.Logger templateCache *TemplateCache //Services used by HTTP routes @@ -33,21 +29,5 @@ func NewRatchetApp(logger *slog.Logger, tc *TemplateCache, db *sql.DB, sm *scs.S rs.formDecoder = form.NewDecoder() rs.templateCache = tc rs.sessionManager = sm - // TODO implement middleware that disables directory listings - // This line was superceded by using the embedded filesystem - // fileServer := http.FileServer(http.Dir("./ui/static/")) - router := http.NewServeMux() - - // Subtree pattern for static assets - // This line was superceded by using the embedded filesystem - // router.Handle("GET /static/", http.StripPrefix("/static/", fileServer)) - router.Handle("GET /static/", http.FileServerFS(ui.Files)) - - // Mux Router implements the Handler interface. AKA it has a ServeHTTP receiver. - // SEE we can really clean things up by moving this into routes.go and handlers.go - wrappedMux := addRoutes(router, rs.logger, rs.templateCache, db, rs.formDecoder, sm, rs.userService, rs.snippetService) - rs.Handler = CommonHeaderMiddleware(wrappedMux) - rs.Handler = RequestLoggingMiddleware(rs.Handler, logger) - rs.Handler = RecoveryMiddleware(rs.Handler) return rs }