Skip to content

Instantly share code, notes, and snippets.

@iporsut
Last active December 24, 2023 06:14
Show Gist options
  • Save iporsut/b63fca1b3790d2989c3163e96e7470de to your computer and use it in GitHub Desktop.
Save iporsut/b63fca1b3790d2989c3163e96e7470de to your computer and use it in GitHub Desktop.
go1.22 net/http package new feature support path params pattern
package main
import (
"encoding/json"
"net/http"
"slices"
"sync"
)
type TODO struct {
UUID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Completed bool `json:"completed"`
}
type TODOList struct {
TODOs []*TODO
mu sync.Mutex
}
func (t *TODOList) Add(todo *TODO) {
t.mu.Lock()
defer t.mu.Unlock()
t.TODOs = append(t.TODOs, todo)
}
func (t *TODOList) Remove(uuid string) {
t.mu.Lock()
defer t.mu.Unlock()
t.TODOs = slices.DeleteFunc(t.TODOs, func(todo *TODO) bool {
return todo.UUID == uuid
})
}
func (t *TODOList) Get(uuid string) *TODO {
t.mu.Lock()
defer t.mu.Unlock()
i := slices.IndexFunc(t.TODOs, func(todo *TODO) bool {
return todo.UUID == uuid
})
if i == -1 {
return nil
}
return t.TODOs[i]
}
func (t *TODOList) Update(todo *TODO) {
t.mu.Lock()
defer t.mu.Unlock()
i := slices.IndexFunc(t.TODOs, func(t *TODO) bool {
return t.UUID == todo.UUID
})
if i == -1 {
return
}
t.TODOs[i] = todo
}
func (t *TODOList) All() []*TODO {
t.mu.Lock()
defer t.mu.Unlock()
return t.TODOs
}
func (t *TODOList) Completed() []*TODO {
t.mu.Lock()
defer t.mu.Unlock()
var completed []*TODO
for _, todo := range t.TODOs {
if todo.Completed {
completed = append(completed, todo)
}
}
return completed
}
func (t *TODOList) Pending() []*TODO {
t.mu.Lock()
defer t.mu.Unlock()
var pending []*TODO
for _, todo := range t.TODOs {
if !todo.Completed {
pending = append(pending, todo)
}
}
return pending
}
func (t *TODOList) Clear() {
t.mu.Lock()
defer t.mu.Unlock()
t.TODOs = nil
}
func (t *TODOList) Toggle(uuid string) {
t.mu.Lock()
defer t.mu.Unlock()
i := slices.IndexFunc(t.TODOs, func(todo *TODO) bool {
return todo.UUID == uuid
})
if i == -1 {
return
}
t.TODOs[i].Completed = !t.TODOs[i].Completed
}
func (t *TODOList) ToggleAll() {
t.mu.Lock()
defer t.mu.Unlock()
for _, todo := range t.TODOs {
todo.Completed = !todo.Completed
}
}
func (t *TODOList) MarkComplete(uuid string) {
t.mu.Lock()
defer t.mu.Unlock()
i := slices.IndexFunc(t.TODOs, func(todo *TODO) bool {
return todo.UUID == uuid
})
if i == -1 {
return
}
t.TODOs[i].Completed = true
}
func (t *TODOList) CompleteAll() {
t.mu.Lock()
defer t.mu.Unlock()
for _, todo := range t.TODOs {
todo.Completed = true
}
}
func (t *TODOList) MarkPending(uuid string) {
t.mu.Lock()
defer t.mu.Unlock()
i := slices.IndexFunc(t.TODOs, func(todo *TODO) bool {
return todo.UUID == uuid
})
if i == -1 {
return
}
t.TODOs[i].Completed = false
}
func (t *TODOList) PendingAll() {
t.mu.Lock()
defer t.mu.Unlock()
for _, todo := range t.TODOs {
todo.Completed = false
}
}
func main() {
items := &TODOList{TODOs: []*TODO{}}
http.HandleFunc("/todos", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
err := json.NewEncoder(w).Encode(items.All())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
case "POST":
var todo TODO
err := json.NewDecoder(r.Body).Decode(&todo)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
items.Add(&todo)
}
})
http.HandleFunc("/todos/{uuid}", func(w http.ResponseWriter, r *http.Request) {
uuid := r.PathValue("uuid")
switch r.Method {
case "GET":
todo := items.Get(uuid)
if todo == nil {
http.Error(w, "Not Found", http.StatusNotFound)
return
}
err := json.NewEncoder(w).Encode(todo)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
case "PUT":
var todo TODO
err := json.NewDecoder(r.Body).Decode(&todo)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
todo.UUID = uuid
items.Update(&todo)
case "DELETE":
items.Remove(uuid)
}
})
http.HandleFunc("/todos/{uuid}/toggle", func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
return
}
uuid := r.PathValue("uuid")
items.Toggle(uuid)
})
http.ListenAndServe(":8080", nil)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment