Files
restxlsx/internal/api/rest.go
T
2026-06-10 13:01:57 +02:00

175 lines
4.1 KiB
Go

package api
import (
"encoding/json"
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/restxlsx/restxlsx/internal/excel"
"github.com/restxlsx/restxlsx/internal/logger"
)
type RestAPI struct {
engine *excel.Engine
log *logger.Logger
}
func NewRestAPI(engine *excel.Engine, log *logger.Logger) *RestAPI {
return &RestAPI{engine: engine, log: log}
}
func (h *RestAPI) ListTables(w http.ResponseWriter, r *http.Request) {
h.engine.Lock()
tables := h.engine.ListTables()
h.engine.Unlock()
writeJSON(w, 200, map[string][]string{"tables": tables})
}
func (h *RestAPI) ListRecords(w http.ResponseWriter, r *http.Request) {
table := chi.URLParam(r, "table")
h.engine.Lock()
t := h.engine.GetTable(table)
if t == nil {
h.engine.Unlock()
writeJSON(w, 404, map[string]string{"error": "table not found"})
return
}
rows := t.Rows
h.engine.Unlock()
writeJSON(w, 200, rows)
}
func (h *RestAPI) GetRecord(w http.ResponseWriter, r *http.Request) {
table := chi.URLParam(r, "table")
id := chi.URLParam(r, "id")
h.engine.Lock()
t := h.engine.GetTable(table)
if t == nil {
h.engine.Unlock()
writeJSON(w, 404, map[string]string{"error": "table not found"})
return
}
idCol := h.engine.IDColumn(table)
for _, row := range t.Rows {
if fmt.Sprintf("%v", row[idCol]) == id {
h.engine.Unlock()
writeJSON(w, 200, row)
return
}
}
h.engine.Unlock()
writeJSON(w, 404, map[string]string{"error": "record not found"})
}
func (h *RestAPI) CreateRecord(w http.ResponseWriter, r *http.Request) {
table := chi.URLParam(r, "table")
var rec map[string]any
if err := json.NewDecoder(r.Body).Decode(&rec); err != nil {
writeJSON(w, 400, map[string]string{"error": "invalid JSON: " + err.Error()})
return
}
h.engine.Lock()
defer h.engine.Unlock()
t := h.engine.GetTable(table)
if t == nil {
writeJSON(w, 404, map[string]string{"error": "table not found"})
return
}
idCol := h.engine.IDColumn(table)
if idCol != "" {
if _, ok := rec[idCol]; !ok {
rec[idCol] = len(t.Rows) + 1
}
}
t.Rows = append(t.Rows, rec)
if err := h.engine.Flush(); err != nil {
writeJSON(w, 503, map[string]string{"error": "flush failed: " + err.Error()})
return
}
writeJSON(w, 201, rec)
}
func (h *RestAPI) UpdateRecord(w http.ResponseWriter, r *http.Request) {
table := chi.URLParam(r, "table")
id := chi.URLParam(r, "id")
var rec map[string]any
if err := json.NewDecoder(r.Body).Decode(&rec); err != nil {
writeJSON(w, 400, map[string]string{"error": "invalid JSON: " + err.Error()})
return
}
h.engine.Lock()
defer h.engine.Unlock()
t := h.engine.GetTable(table)
if t == nil {
writeJSON(w, 404, map[string]string{"error": "table not found"})
return
}
idCol := h.engine.IDColumn(table)
for i, row := range t.Rows {
if fmt.Sprintf("%v", row[idCol]) == id {
for k, v := range rec {
t.Rows[i][k] = v
}
if err := h.engine.Flush(); err != nil {
writeJSON(w, 503, map[string]string{"error": "flush failed: " + err.Error()})
return
}
writeJSON(w, 200, t.Rows[i])
return
}
}
writeJSON(w, 404, map[string]string{"error": "record not found"})
}
func (h *RestAPI) DeleteRecord(w http.ResponseWriter, r *http.Request) {
table := chi.URLParam(r, "table")
id := chi.URLParam(r, "id")
h.engine.Lock()
defer h.engine.Unlock()
t := h.engine.GetTable(table)
if t == nil {
writeJSON(w, 404, map[string]string{"error": "table not found"})
return
}
idCol := h.engine.IDColumn(table)
for i, row := range t.Rows {
if fmt.Sprintf("%v", row[idCol]) == id {
t.Rows = append(t.Rows[:i], t.Rows[i+1:]...)
if err := h.engine.Flush(); err != nil {
writeJSON(w, 503, map[string]string{"error": "flush failed: " + err.Error()})
return
}
writeJSON(w, 204, nil)
return
}
}
writeJSON(w, 404, map[string]string{"error": "record not found"})
}
type responseWriter struct {
http.ResponseWriter
status int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.status = code
rw.ResponseWriter.WriteHeader(code)
}
func writeJSON(w http.ResponseWriter, status int, data any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
if data != nil {
json.NewEncoder(w).Encode(data)
}
}