From 571345cda7420595335111f73626cdfe39baa580 Mon Sep 17 00:00:00 2001 From: Yevhen Pavlov Date: Sat, 23 Nov 2024 23:06:05 +0200 Subject: [PATCH] refactor: Rework handlers --- cmd/app/main.go | 4 +- internal/web/handlers.go | 1 - internal/web/handlers/base.go | 37 +++++++++ internal/web/handlers/notes.go | 101 +++++++++++++++++++++++ internal/web/web.go | 142 ++++----------------------------- 5 files changed, 157 insertions(+), 128 deletions(-) delete mode 100644 internal/web/handlers.go create mode 100644 internal/web/handlers/base.go create mode 100644 internal/web/handlers/notes.go diff --git a/cmd/app/main.go b/cmd/app/main.go index 45cf651..70d32b0 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -2,9 +2,11 @@ package main import ( "github.com/sonjek/go-templ-htmx-picocss-example/internal/web" + "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/handlers" ) func main() { - webServer := web.NewServer() + handlers := handlers.NewHandler() + webServer := web.NewServer(handlers) webServer.Start() } diff --git a/internal/web/handlers.go b/internal/web/handlers.go deleted file mode 100644 index efb3895..0000000 --- a/internal/web/handlers.go +++ /dev/null @@ -1 +0,0 @@ -package web diff --git a/internal/web/handlers/base.go b/internal/web/handlers/base.go new file mode 100644 index 0000000..d887d0d --- /dev/null +++ b/internal/web/handlers/base.go @@ -0,0 +1,37 @@ +package handlers + +import ( + "fmt" + "net/http" + + "github.com/a-h/templ" + "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/templ/components" + "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/templ/page" + "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/templ/view" +) + +type Handlers struct { +} + +func NewHandler() *Handlers { + return &Handlers{} +} + +func handleRenderError(err error) { + if err != nil { + fmt.Println("Render error: ", err) + } +} + +// Set header and render error message +func sendErrorMsg(w http.ResponseWriter, r *http.Request, errorMsg string) { + w.WriteHeader(http.StatusBadRequest) + handleRenderError(components.ErrorMsg(errorMsg).Render(r.Context(), w)) +} + +func (h *Handlers) Page404(w http.ResponseWriter, r *http.Request) { + templ.Handler( + page.Index(view.NotFoundComponent()), + templ.WithStatus(http.StatusNotFound), + ).ServeHTTP(w, r) +} diff --git a/internal/web/handlers/notes.go b/internal/web/handlers/notes.go new file mode 100644 index 0000000..646a175 --- /dev/null +++ b/internal/web/handlers/notes.go @@ -0,0 +1,101 @@ +package handlers + +import ( + "net/http" + "strconv" + "time" + + "github.com/sonjek/go-templ-htmx-picocss-example/internal/notes" + "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/templ/components" + "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/templ/page" + "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/templ/view" +) + +func (h *Handlers) Notes(w http.ResponseWriter, r *http.Request) { + handleRenderError(page.Index(view.NotesView(notes.GetLatestNotes())).Render(r.Context(), w)) +} + +func (h *Handlers) MoreNotes(w http.ResponseWriter, r *http.Request) { + noteID := -1 + if p := r.URL.Query().Get("note"); p != "" { + if parsedNoteID, err := strconv.Atoi(p); err == nil { + noteID = parsedNoteID + } + } + + if noteID == -1 { + sendErrorMsg(w, r, "Note is empty") + return + } + + notesOnPage := notes.GetNextNotes(noteID) + + time.Sleep(250 * time.Millisecond) + handleRenderError(components.NotesList(notesOnPage).Render(r.Context(), w)) +} + +func (h *Handlers) AddNoteModal(w http.ResponseWriter, r *http.Request) { + handleRenderError(components.ModalAddNote().Render(r.Context(), w)) +} + +func (h *Handlers) AddNote(w http.ResponseWriter, r *http.Request) { + if r.FormValue("title") == "" { + sendErrorMsg(w, r, "Title is empty") + return + } + + if r.FormValue("body") == "" { + sendErrorMsg(w, r, "Body is empty") + return + } + + note := notes.Add(notes.CreateNote{ + Title: r.FormValue("title"), + Body: r.FormValue("body"), + }) + + time.Sleep(250 * time.Millisecond) + + handleRenderError(components.NoteItem(note).Render(r.Context(), w)) +} + +func (h *Handlers) EditNoteModal(w http.ResponseWriter, r *http.Request) { + note, err := notes.GetNoteByID(r.PathValue("id")) + if err != nil { + sendErrorMsg(w, r, err.Error()) + return + } + + handleRenderError(components.ModalEditNote(note).Render(r.Context(), w)) +} + +func (h *Handlers) EditNote(w http.ResponseWriter, r *http.Request) { + if r.FormValue("title") == "" { + sendErrorMsg(w, r, "Title is empty") + return + } + + if r.FormValue("body") == "" { + sendErrorMsg(w, r, "Body is empty") + return + } + + note, err := notes.GetNoteByID(r.PathValue("id")) + if err != nil { + sendErrorMsg(w, r, err.Error()) + return + } + + note.Title = r.FormValue("title") + note.Body = r.FormValue("body") + notes.Update(note) + + time.Sleep(250 * time.Millisecond) + handleRenderError(components.NoteItem(note).Render(r.Context(), w)) +} + +func (h *Handlers) DeleteNote(w http.ResponseWriter, r *http.Request) { + if err := notes.Delete(r.PathValue("id")); err != nil { + sendErrorMsg(w, r, err.Error()) + } +} diff --git a/internal/web/web.go b/internal/web/web.go index a549669..73ba6a3 100644 --- a/internal/web/web.go +++ b/internal/web/web.go @@ -5,127 +5,23 @@ import ( "fmt" "io/fs" "net/http" - "strconv" "time" - "github.com/a-h/templ" - "github.com/sonjek/go-templ-htmx-picocss-example/internal/notes" + "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/handlers" "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/middleware" - "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/templ/components" - "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/templ/page" - "github.com/sonjek/go-templ-htmx-picocss-example/internal/web/templ/view" ) type Server struct { - mux *http.ServeMux + mux *http.ServeMux + handlers *handlers.Handlers } -func NewServer() *Server { +func NewServer(h *handlers.Handlers) *Server { mux := http.NewServeMux() return &Server{ - mux: mux, - } -} - -func handleRenderError(err error) { - if err != nil { - fmt.Println("Render error: ", err) - } -} - -// Set header and render error message -func sendErrorMsg(w http.ResponseWriter, r *http.Request, errorMsg string) { - w.WriteHeader(http.StatusBadRequest) - handleRenderError(components.ErrorMsg(errorMsg).Render(r.Context(), w)) -} - -func notesFunc(w http.ResponseWriter, r *http.Request) { - handleRenderError(page.Index(view.NotesView(notes.GetLatestNotes())).Render(r.Context(), w)) -} - -func moreNotesFunc(w http.ResponseWriter, r *http.Request) { - noteID := -1 - if p := r.URL.Query().Get("note"); p != "" { - if parsedNoteID, err := strconv.Atoi(p); err == nil { - noteID = parsedNoteID - } - } - - if noteID == -1 { - sendErrorMsg(w, r, "Note is empty") - return - } - - notesOnPage := notes.GetNextNotes(noteID) - - time.Sleep(250 * time.Millisecond) - handleRenderError(components.NotesList(notesOnPage).Render(r.Context(), w)) -} - -func addNoteModalFunc(w http.ResponseWriter, r *http.Request) { - handleRenderError(components.ModalAddNote().Render(r.Context(), w)) -} - -func addNoteFunc(w http.ResponseWriter, r *http.Request) { - if r.FormValue("title") == "" { - sendErrorMsg(w, r, "Title is empty") - return - } - - if r.FormValue("body") == "" { - sendErrorMsg(w, r, "Body is empty") - return - } - - note := notes.Add(notes.CreateNote{ - Title: r.FormValue("title"), - Body: r.FormValue("body"), - }) - - time.Sleep(250 * time.Millisecond) - - handleRenderError(components.NoteItem(note).Render(r.Context(), w)) -} - -func editNoteModalFunc(w http.ResponseWriter, r *http.Request) { - note, err := notes.GetNoteByID(r.PathValue("id")) - if err != nil { - sendErrorMsg(w, r, err.Error()) - return - } - - handleRenderError(components.ModalEditNote(note).Render(r.Context(), w)) -} - -func editNoteFunc(w http.ResponseWriter, r *http.Request) { - if r.FormValue("title") == "" { - sendErrorMsg(w, r, "Title is empty") - return - } - - if r.FormValue("body") == "" { - sendErrorMsg(w, r, "Body is empty") - return - } - - note, err := notes.GetNoteByID(r.PathValue("id")) - if err != nil { - sendErrorMsg(w, r, err.Error()) - return - } - - note.Title = r.FormValue("title") - note.Body = r.FormValue("body") - notes.Update(note) - - time.Sleep(250 * time.Millisecond) - handleRenderError(components.NoteItem(note).Render(r.Context(), w)) -} - -func deleteNoteFunc(w http.ResponseWriter, r *http.Request) { - if err := notes.Delete(r.PathValue("id")); err != nil { - sendErrorMsg(w, r, err.Error()) + mux: mux, + handlers: h, } } @@ -138,26 +34,20 @@ func (ws Server) Start() { // If not, redirect to the custom 404 page _, pattern := ws.mux.Handler(r) if r.URL.Path != pattern { - http.Redirect(w, r, "/404", http.StatusSeeOther) - return + ws.handlers.Page404(w, r) } - // Serve the index handler - notesFunc(w, r) + // Redirect from site index to notes page + http.Redirect(w, r, "/notes", http.StatusSeeOther) }) - ws.mux.Handle("/404", templ.Handler(page.Index(view.NotFoundComponent()), - templ.WithStatus(http.StatusNotFound))) - - ws.mux.HandleFunc("/notes", notesFunc) - ws.mux.HandleFunc("/notes/load-more", moreNotesFunc) - - ws.mux.HandleFunc("/add", addNoteModalFunc) - ws.mux.HandleFunc("POST /notes", addNoteFunc) - - ws.mux.HandleFunc("/edit/{id}", editNoteModalFunc) - ws.mux.HandleFunc("PUT /note/{id}", editNoteFunc) - ws.mux.HandleFunc("DELETE /note/{id}", deleteNoteFunc) + ws.mux.HandleFunc("/notes", ws.handlers.Notes) + ws.mux.HandleFunc("/notes/load-more", ws.handlers.MoreNotes) + ws.mux.HandleFunc("/add", ws.handlers.AddNoteModal) + ws.mux.HandleFunc("POST /notes", ws.handlers.AddNote) + ws.mux.HandleFunc("/edit/{id}", ws.handlers.EditNoteModal) + ws.mux.HandleFunc("PUT /note/{id}", ws.handlers.EditNote) + ws.mux.HandleFunc("DELETE /note/{id}", ws.handlers.DeleteNote) // Use embed.FS to create a file system from the embedded files ws.mux.Handle("/static/", http.FileServerFS(staticFiles))