refactor to server struct

master
Jason Staten 2 years ago
parent 7e01f3937d
commit a81cd79a90

@ -19,12 +19,6 @@ type Todo struct {
Completed bool Completed bool
} }
type ViewModel struct {
Todos []Todo
Only string
Incomplete int
}
func filterSlice[T any](xs []T, pred func(T) bool) []T { func filterSlice[T any](xs []T, pred func(T) bool) []T {
result := make([]T, 0, len(xs)) result := make([]T, 0, len(xs))
for _, element := range xs { for _, element := range xs {
@ -48,113 +42,145 @@ func countSlice[T any](xs []T, pred func(T) bool) int {
return count return count
} }
func main() { type server struct {
todos := make([]Todo, 0, 10) views *views.Views
router *http.ServeMux
todos []Todo
}
t := views.New() func newServer() *server {
list := t.Renderer("list.html") srv := &server{
http.Handle("/public/", http.FileServer(http.FS(publicFS))) views: views.New(),
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { router: http.NewServeMux(),
todos: make([]Todo, 0, 10),
}
srv.routes()
return srv
}
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.router.ServeHTTP(w, r)
}
func (s *server) AddTodo(t Todo) {
s.todos = append(s.todos, t)
}
func (s *server) HandleList() http.HandlerFunc {
type viewModel struct {
Todos []Todo
Only string
Incomplete int
}
list := s.views.Renderer("list.html")
return func(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query() q := r.URL.Query()
renderTodos := todos renderTodos := s.todos
only := q.Get("only") only := q.Get("only")
if only == "active" { if only == "active" {
renderTodos = filterSlice(todos, func(todo Todo) bool { return !todo.Completed }) renderTodos = filterSlice(s.todos, func(todo Todo) bool { return !todo.Completed })
} }
if only == "completed" { if only == "completed" {
renderTodos = filterSlice(todos, func(todo Todo) bool { return todo.Completed }) renderTodos = filterSlice(s.todos, func(todo Todo) bool { return todo.Completed })
} }
incomplete := countSlice(todos, func(todo Todo) bool { return !todo.Completed }) incomplete := countSlice(s.todos, func(todo Todo) bool { return !todo.Completed })
vm := ViewModel{ vm := viewModel{
Todos: renderTodos, Todos: renderTodos,
Only: only, Only: only,
Incomplete: incomplete, Incomplete: incomplete,
} }
list(w, r, vm) list(w, r, vm)
}) }
http.HandleFunc("/todo", func(w http.ResponseWriter, r *http.Request) { }
if r.Method != "POST" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
if err := r.ParseForm(); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
func (s *server) HandleCreate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
title := r.Form.Get("title") title := r.Form.Get("title")
todos = append(todos, Todo{ s.AddTodo(Todo{
Id: strconv.Itoa(rand.Int()), Id: strconv.Itoa(rand.Int()),
Title: title, Title: title,
}) })
w.Header().Set("Location", "/") http.Redirect(w, r, "/", http.StatusSeeOther)
w.WriteHeader(http.StatusSeeOther) }
}) }
http.HandleFunc("/toggle", func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
if err := r.ParseForm(); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
func (s *server) HandleToggle() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id := r.Form.Get("id") id := r.Form.Get("id")
for i, todo := range todos { for i, todo := range s.todos {
if todo.Id == id { if todo.Id == id {
todo.Completed = !todo.Completed todo.Completed = !todo.Completed
todos[i] = todo s.todos[i] = todo
} }
} }
w.Header().Set("Location", "/") http.Redirect(w, r, "/", http.StatusSeeOther)
w.WriteHeader(http.StatusSeeOther) }
}) }
http.HandleFunc("/destroy", func(w http.ResponseWriter, r *http.Request) { func (s *server) HandleDestroy() http.HandlerFunc {
if r.Method != "POST" { return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusMethodNotAllowed) id := r.Form.Get("id")
return s.todos = filterSlice(s.todos, func(t Todo) bool { return t.Id != id })
}
if err := r.ParseForm(); err != nil { http.Redirect(w, r, "/", http.StatusSeeOther)
w.WriteHeader(http.StatusBadRequest) }
return }
}
id := r.Form.Get("id") func (s *server) HandleClear() http.HandlerFunc {
todos = filterSlice(todos, func(t Todo) bool { return t.Id != id }) return func(w http.ResponseWriter, r *http.Request) {
s.todos = filterSlice(s.todos, func(t Todo) bool { return !t.Completed })
w.Header().Set("Location", "/") http.Redirect(w, r, "/", http.StatusSeeOther)
w.WriteHeader(http.StatusSeeOther) }
}) }
func (s *server) routes() {
s.router.Handle("/public/", http.FileServer(http.FS(publicFS)))
s.router.HandleFunc("/", s.HandleList())
s.router.HandleFunc("/todo", parseForm(ensureMethod("POST", s.HandleCreate())))
s.router.HandleFunc("/toggle", parseForm(ensureMethod("POST", s.HandleToggle())))
s.router.HandleFunc("/destroy", parseForm(ensureMethod("POST", s.HandleDestroy())))
s.router.HandleFunc("/clear", ensureMethod("POST", s.HandleClear()))
}
func run() error {
srv := newServer()
log.Print("Running on 8080")
return http.ListenAndServe(":8080", srv)
}
func main() {
log.Fatal(run())
}
http.HandleFunc("/clear", func(w http.ResponseWriter, r *http.Request) { func ensureMethod(method string, next http.Handler) http.HandlerFunc {
if r.Method != "POST" { return func(w http.ResponseWriter, r *http.Request) {
if r.Method != method {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return
} }
next.ServeHTTP(w, r)
}
}
func parseForm(next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Bad Request"))
return return
} }
todos = filterSlice(todos, func(t Todo) bool { return !t.Completed }) next.ServeHTTP(w, r)
}
w.Header().Set("Location", "/")
w.WriteHeader(http.StatusSeeOther)
})
log.Print("Running on 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
} }

Loading…
Cancel
Save