From cc317ca66163748b2c43285c73467789aded62b0 Mon Sep 17 00:00:00 2001 From: Siesta <124433727+siestaw@users.noreply.github.com> Date: Sun, 27 Jul 2025 22:57:43 +0200 Subject: [PATCH] feat: improve responses --- cmd/internal/middleware/auth.go | 6 +++--- cmd/internal/models/models.go | 18 +++++++++++------ cmd/internal/routes/colors.go | 31 ++++++++++++++---------------- cmd/internal/routes/controllers.go | 18 +++++++---------- cmd/utils/utils.go | 31 +++++++++++++++++++----------- 5 files changed, 56 insertions(+), 48 deletions(-) diff --git a/cmd/internal/middleware/auth.go b/cmd/internal/middleware/auth.go index 18a43f0..524134e 100644 --- a/cmd/internal/middleware/auth.go +++ b/cmd/internal/middleware/auth.go @@ -11,9 +11,9 @@ func WithAdminAuth(handlerFunc http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("Authorization") if !db.IsAdmin(token) { - utils.HTTPResponseHandler(w, r, http.StatusUnauthorized, "Invalid token") - return + utils.ErrorResponse(w, http.StatusUnauthorized, "Invalid token") + return } handlerFunc(w, r) } -} \ No newline at end of file +} diff --git a/cmd/internal/models/models.go b/cmd/internal/models/models.go index c8675a8..9c87f8b 100644 --- a/cmd/internal/models/models.go +++ b/cmd/internal/models/models.go @@ -10,7 +10,6 @@ type HTTPConfig struct { Cooldown float64 `json:"cooldown"` } - type Config struct { HTTP HTTPConfig `json:"http"` FileLogging bool `json:"fileLogging"` @@ -18,11 +17,10 @@ type Config struct { } type HTTPResponse struct { + Success bool `json:"success"` + Error string `json:"error,omitempty"` Timestamp string `json:"timestamp"` - Status int `json:"status"` - Text string `json:"text"` - Message string `json:"message"` - Path string `json:"path"` + Data any `json:"data,omitempty"` } type LampState struct { @@ -37,4 +35,12 @@ type LampUpdateRequest struct { type ControllerRequests struct { ID int `json:"ID"` -} \ No newline at end of file +} + +type DeleteData struct { + Deleted int `json:"deleted"` +} + +type CreateData struct { + Created int `json:"created"` +} diff --git a/cmd/internal/routes/colors.go b/cmd/internal/routes/colors.go index e7fc676..100a10a 100644 --- a/cmd/internal/routes/colors.go +++ b/cmd/internal/routes/colors.go @@ -16,7 +16,7 @@ import ( func RegisterColorRoutes(mux *http.ServeMux) { mux.HandleFunc("GET /api/v1/colors/{ID}", middleware.WithAdminAuth(getCurrent)) mux.HandleFunc("PUT /api/v1/colors/{ID}", middleware.WithAdminAuth(setCurrent)) -// mux.HandleFunc("WS /api/v1/ws/colors/{ID}", setCurrentWebsocket) + // mux.HandleFunc("WS /api/v1/ws/colors/{ID}", setCurrentWebsocket) } func getCurrent(w http.ResponseWriter, r *http.Request) { @@ -25,23 +25,22 @@ func getCurrent(w http.ResponseWriter, r *http.Request) { idStr := r.PathValue("ID") id, err := utils.IDtoInt(idStr) if err != nil { - utils.HTTPResponseHandler(w, r, http.StatusBadRequest, err.Error()) + utils.ErrorResponse(w, http.StatusBadRequest, err.Error()) return } - + if !db.ControllerExists(id) { - utils.HTTPResponseHandler(w, r, http.StatusBadRequest, "Lamp does not exist") + utils.ErrorResponse(w, http.StatusNotFound, "Lamp does not exist") return } state, err := db.ViewColor(id) if err != nil { - utils.HTTPResponseHandler(w, r, http.StatusBadRequest, err.Error()) + utils.ErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(state) + utils.SuccessResponse(w, http.StatusOK, state) } func setCurrent(w http.ResponseWriter, r *http.Request) { @@ -50,44 +49,42 @@ func setCurrent(w http.ResponseWriter, r *http.Request) { idStr := r.PathValue("ID") id, err := utils.IDtoInt(idStr) if err != nil { - utils.HTTPResponseHandler(w, r, http.StatusBadRequest, err.Error()) + utils.ErrorResponse(w, http.StatusBadRequest, err.Error()) return } if !db.ControllerExists(id) { - utils.HTTPResponseHandler(w, r, http.StatusBadRequest, "Lamp does not exist") + utils.ErrorResponse(w, http.StatusBadRequest, "Lamp does not exist") return } currentState, err := db.ViewColor(id) if err != nil { - utils.HTTPResponseHandler(w, r, http.StatusInternalServerError, "Failed to get current lamp color") + utils.ErrorResponse(w, http.StatusInternalServerError, "Failed to get current lamp color") return } if time.Since(currentState.UpdatedAt).Seconds() < config.AppConfig.HTTP.Cooldown { - utils.HTTPResponseHandler(w, r, http.StatusTooManyRequests, "Slow down!") + utils.ErrorResponse(w, http.StatusTooManyRequests, "Slow down!") return } var req models.LampUpdateRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { logger.HTTPLogger.Print(err) - utils.HTTPResponseHandler(w, r, http.StatusBadRequest, "Invalid JSON") + utils.ErrorResponse(w, http.StatusBadRequest, "Invalid JSON") return } err = db.SetColor(id, req.Color) if err != nil { logger.HTTPLogger.Printf("Could not update lamp %d: %s", id, err) - utils.HTTPResponseHandler(w, r, http.StatusInternalServerError, err.Error()) + utils.ErrorResponse(w, http.StatusInternalServerError, err.Error()) return } updatedState := currentState updatedState.Color = req.Color updatedState.UpdatedAt = time.Now() + utils.SuccessResponse(w, http.StatusOK, updatedState) - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(updatedState) - logger.HTTPLogger.Printf("Lamp %d updated to color %s", id, req.Color) -} \ No newline at end of file +} diff --git a/cmd/internal/routes/controllers.go b/cmd/internal/routes/controllers.go index 5fd85e5..1551fab 100644 --- a/cmd/internal/routes/controllers.go +++ b/cmd/internal/routes/controllers.go @@ -5,7 +5,6 @@ import ( "net/http" "github.com/siestaw/laterna/server/cmd/internal/db" - "github.com/siestaw/laterna/server/cmd/internal/logger" "github.com/siestaw/laterna/server/cmd/internal/middleware" "github.com/siestaw/laterna/server/cmd/internal/models" "github.com/siestaw/laterna/server/cmd/utils" @@ -20,28 +19,25 @@ func createController(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() ID, err := db.CreateController() if err != nil { - utils.HTTPResponseHandler(w, r, http.StatusInternalServerError, "An error occured. Check the server logs for more information") + utils.ErrorResponse(w, http.StatusInternalServerError, "An error occured. Check the server logs for more information") } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(map[string]int64{"ID": ID}) + utils.SuccessResponse(w, http.StatusOK, models.CreateData{Created: int(ID)}) } func deleteController(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() var req models.ControllerRequests if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - logger.HTTPLogger.Print(err) - utils.HTTPResponseHandler(w, r, http.StatusBadRequest, "Invalid JSON") + utils.ErrorResponse(w, http.StatusBadRequest, "Invalid JSON") return } if !db.ControllerExists(req.ID) || req.ID <= 0 { - utils.HTTPResponseHandler(w, r, http.StatusBadRequest,"Invalid ID") + utils.ErrorResponse(w, http.StatusBadRequest, "Invalid ID") return } if db.DeleteController(req.ID) != nil { - utils.HTTPResponseHandler(w, r, http.StatusInternalServerError,"An error occured. Check the server logs for more information") + utils.ErrorResponse(w, http.StatusInternalServerError, "An error occured. Check the server logs for more information") return } - utils.HTTPResponseHandler(w, r, http.StatusOK, "Success") -} \ No newline at end of file + utils.SuccessResponse(w, http.StatusOK, models.DeleteData{Deleted: req.ID}) +} diff --git a/cmd/utils/utils.go b/cmd/utils/utils.go index 34eba8d..fbfc0d9 100644 --- a/cmd/utils/utils.go +++ b/cmd/utils/utils.go @@ -49,16 +49,25 @@ func ValidateToken(providedToken string, storedHash string) bool { return err == nil } -func HTTPResponseHandler(w http.ResponseWriter, r *http.Request, status int, message string) { - timestamp := time.Now().Format("2006-01-02_15-04-05") - errResp := models.HTTPResponse{ - Timestamp: timestamp, - Status: status, - Text: http.StatusText(status), - Message: message, - Path: r.URL.Path, - } +func WriteJSONResponse(w http.ResponseWriter, statusCode int, res models.HTTPResponse) { w.Header().Set("Content-Type", "application/json") - w.WriteHeader(status) - json.NewEncoder(w).Encode(errResp) + w.WriteHeader(statusCode) + + res.Timestamp = time.Now().UTC().Format(time.RFC3339) + + json.NewEncoder(w).Encode(res) +} + +func SuccessResponse(w http.ResponseWriter, statusCode int, data any) { + WriteJSONResponse(w, statusCode, models.HTTPResponse{ + Success: true, + Data: data, + }) +} + +func ErrorResponse(w http.ResponseWriter, statusCode int, err string) { + WriteJSONResponse(w, statusCode, models.HTTPResponse{ + Success: false, + Error: err, + }) }