From a47f703910b6605b2fa7258f705e6c93477d6b79 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sat, 28 Mar 2026 14:33:36 +0300 Subject: [PATCH] fix: nil slices return [] not null in all API responses --- internal/api/projects.go | 3 --- internal/api/response.go | 9 +++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/api/projects.go b/internal/api/projects.go index 8aa73de..029f19d 100644 --- a/internal/api/projects.go +++ b/internal/api/projects.go @@ -27,9 +27,6 @@ func (s *Server) listProjects(w http.ResponseWriter, r *http.Request) { respondError(w, http.StatusInternalServerError, "failed to list projects: "+err.Error()) return } - if projects == nil { - projects = []store.Project{} - } respondJSON(w, http.StatusOK, projects) } diff --git a/internal/api/response.go b/internal/api/response.go index ea82ec4..2eedd8b 100644 --- a/internal/api/response.go +++ b/internal/api/response.go @@ -4,6 +4,7 @@ import ( "encoding/json" "log/slog" "net/http" + "reflect" ) // envelope is the standard API response wrapper. @@ -14,7 +15,15 @@ type envelope struct { } // respondJSON writes a JSON success response with the given status code and data. +// Nil slices are converted to empty arrays to avoid "null" in JSON output. func respondJSON(w http.ResponseWriter, status int, data any) { + // Convert nil slices to empty arrays so JSON encodes as [] not null. + if data != nil { + v := reflect.ValueOf(data) + if v.Kind() == reflect.Slice && v.IsNil() { + data = reflect.MakeSlice(v.Type(), 0, 0).Interface() + } + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) if err := json.NewEncoder(w).Encode(envelope{Success: true, Data: data}); err != nil {