Added Plates and Items Models and connected them with the Frontend
This commit is contained in:
+188
-2
@@ -2,15 +2,44 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"printer.backend/internal/model"
|
||||
"printer.backend/internal/store"
|
||||
)
|
||||
|
||||
// NewHandler returns the API HTTP handler (routes under /).
|
||||
func NewHandler() http.Handler {
|
||||
plates := store.NewPlateStore("")
|
||||
items := store.NewItemStore("")
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("GET /health", health)
|
||||
mux.HandleFunc("GET /", root)
|
||||
return mux
|
||||
mux.HandleFunc("GET /plates", listPlates(plates))
|
||||
mux.HandleFunc("POST /plates", savePlate(plates))
|
||||
mux.HandleFunc("DELETE /plates/{id}", deletePlate(plates))
|
||||
mux.HandleFunc("GET /items", listItems(items))
|
||||
mux.HandleFunc("POST /items", saveItem(items))
|
||||
mux.HandleFunc("DELETE /items/{id}", deleteItem(items))
|
||||
mux.HandleFunc("GET /items/{id}/svg", serveItemSVG(items))
|
||||
return withCORS(mux)
|
||||
}
|
||||
|
||||
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, DELETE, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||
if r.Method == http.MethodOptions {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func health(w http.ResponseWriter, _ *http.Request) {
|
||||
@@ -22,6 +51,163 @@ func root(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(map[string]string{
|
||||
"service": "printer-backend-api",
|
||||
"message": "API placeholder — endpoints folgen",
|
||||
})
|
||||
}
|
||||
|
||||
func listPlates(s *store.PlateStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, _ *http.Request) {
|
||||
plates, err := s.List()
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
if plates == nil {
|
||||
plates = []model.Plate{}
|
||||
}
|
||||
writeJSON(w, http.StatusOK, plates)
|
||||
}
|
||||
}
|
||||
|
||||
type savePlateRequest struct {
|
||||
Name string `json:"name"`
|
||||
WidthMM float64 `json:"width_mm"`
|
||||
HeightMM float64 `json:"height_mm"`
|
||||
MarginTop float64 `json:"margin_top_mm"`
|
||||
MarginRight float64 `json:"margin_right_mm"`
|
||||
MarginBottom float64 `json:"margin_bottom_mm"`
|
||||
MarginLeft float64 `json:"margin_left_mm"`
|
||||
}
|
||||
|
||||
func savePlate(s *store.PlateStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req savePlateRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
if req.WidthMM <= 0 || req.HeightMM <= 0 {
|
||||
writeError(w, http.StatusBadRequest, errors.New("width_mm and height_mm must be positive"))
|
||||
return
|
||||
}
|
||||
|
||||
p := model.Plate{
|
||||
Name: req.Name,
|
||||
WidthMM: req.WidthMM,
|
||||
HeightMM: req.HeightMM,
|
||||
MarginTop: req.MarginTop,
|
||||
MarginRight: req.MarginRight,
|
||||
MarginBottom: req.MarginBottom,
|
||||
MarginLeft: req.MarginLeft,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
}
|
||||
saved, err := s.Save(p)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusCreated, saved)
|
||||
}
|
||||
}
|
||||
|
||||
func deletePlate(s *store.PlateStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.PathValue("id")
|
||||
if id == "" {
|
||||
writeError(w, http.StatusBadRequest, errors.New("id required"))
|
||||
return
|
||||
}
|
||||
if err := s.Delete(id); err != nil {
|
||||
writeError(w, http.StatusNotFound, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func listItems(s *store.ItemStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, _ *http.Request) {
|
||||
list, err := s.List()
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
if list == nil {
|
||||
list = []model.Item{}
|
||||
}
|
||||
writeJSON(w, http.StatusOK, list)
|
||||
}
|
||||
}
|
||||
|
||||
type saveItemRequest struct {
|
||||
Name string `json:"name"`
|
||||
SizeMM float64 `json:"size_mm"`
|
||||
BleedMM float64 `json:"bleed_mm"`
|
||||
MarginMM float64 `json:"margin_mm"`
|
||||
PaddingMM float64 `json:"padding_mm"`
|
||||
}
|
||||
|
||||
func saveItem(s *store.ItemStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req saveItemRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
spec := model.ItemSpec{
|
||||
SizeMM: req.SizeMM,
|
||||
BleedMM: req.BleedMM,
|
||||
MarginMM: req.MarginMM,
|
||||
PaddingMM: req.PaddingMM,
|
||||
}
|
||||
saved, err := s.Create(req.Name, spec)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusCreated, saved)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteItem(s *store.ItemStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.PathValue("id")
|
||||
if id == "" {
|
||||
writeError(w, http.StatusBadRequest, errors.New("id required"))
|
||||
return
|
||||
}
|
||||
if err := s.Delete(id); err != nil {
|
||||
writeError(w, http.StatusNotFound, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func serveItemSVG(s *store.ItemStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.PathValue("id")
|
||||
path, err := s.SVGPath(id)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, err)
|
||||
return
|
||||
}
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "image/svg+xml")
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
_, _ = w.Write(data)
|
||||
}
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, code int, v any) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
_ = json.NewEncoder(w).Encode(v)
|
||||
}
|
||||
|
||||
func writeError(w http.ResponseWriter, code int, err error) {
|
||||
writeJSON(w, code, map[string]string{"error": err.Error()})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user