Files
Курнат Андрей 2315f25754 Initial QSfera import
2026-06-07 10:20:04 +03:00

106 lines
2.8 KiB
Go

package notes
import (
"encoding/json"
"net/http"
"net/url"
"strings"
)
type Server struct {
store Store
}
func NewServer(store Store) http.Handler {
server := &Server{store: store}
mux := http.NewServeMux()
mux.HandleFunc("/healthz", server.handleHealth)
mux.HandleFunc("/api/notes", server.handleCollection)
mux.HandleFunc("/api/notes/", server.handleItem)
return withCORS(mux)
}
func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
return
}
writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
}
func (s *Server) handleCollection(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
writeJSON(w, http.StatusOK, s.store.List())
case http.MethodPost:
var note Note
if err := json.NewDecoder(r.Body).Decode(&note); err != nil {
writeError(w, http.StatusBadRequest, "invalid note json")
return
}
saved, err := s.store.Upsert(note)
if err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
}
writeJSON(w, http.StatusOK, saved)
default:
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
}
}
func (s *Server) handleItem(w http.ResponseWriter, r *http.Request) {
id, err := url.PathUnescape(strings.TrimPrefix(r.URL.Path, "/api/notes/"))
if err != nil || strings.TrimSpace(id) == "" {
writeError(w, http.StatusBadRequest, "note id is required")
return
}
switch r.Method {
case http.MethodPut:
var note Note
if err := json.NewDecoder(r.Body).Decode(&note); err != nil {
writeError(w, http.StatusBadRequest, "invalid note json")
return
}
note.ID = id
saved, err := s.store.Upsert(note)
if err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
}
writeJSON(w, http.StatusOK, saved)
case http.MethodDelete:
if err := s.store.Delete(id); err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
w.WriteHeader(http.StatusNoContent)
default:
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
}
}
func withCORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Accept")
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}
next.ServeHTTP(w, r)
})
}
func writeJSON(w http.ResponseWriter, status int, value any) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(value)
}
func writeError(w http.ResponseWriter, status int, message string) {
writeJSON(w, status, map[string]string{"error": message})
}