From a115ccdc49a7b577e871b2318b27eb480d4e278a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Va=C5=A1ek?= Date: Mon, 18 May 2026 17:18:14 +0200 Subject: [PATCH] fix: return JSON error responses from backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace http.Error (text/plain) with JSON {"message": "..."} responses. The OCP console's appFetch parses this format and surfaces the actual error text in the UI instead of a generic "Internal Server Error". Signed-off-by: Matej VaĊĦek Co-Authored-By: Claude Opus 4.6 --- backend/main.go | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/backend/main.go b/backend/main.go index f122c74..c5212e3 100644 --- a/backend/main.go +++ b/backend/main.go @@ -116,34 +116,40 @@ type fileEntry struct { Type string `json:"type"` } +func jsonError(w http.ResponseWriter, msg string, code int) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + json.NewEncoder(w).Encode(map[string]string{"message": msg}) +} + func handleFuncCreate(w http.ResponseWriter, r *http.Request) { var cfg funcCreateRequest r.Body = http.MaxBytesReader(w, r.Body, 1<<20) // 1 MB limit if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { - http.Error(w, "invalid request body: "+err.Error(), http.StatusBadRequest) + jsonError(w, "invalid request body: "+err.Error(), http.StatusBadRequest) return } if !validName.MatchString(cfg.Name) { - http.Error(w, "invalid function name: must contain only lowercase alphanumeric characters and hyphens", http.StatusBadRequest) + jsonError(w, "invalid function name: must contain only lowercase alphanumeric characters and hyphens", http.StatusBadRequest) return } if !validRuntimes[cfg.Runtime] { - http.Error(w, "invalid runtime: must be one of node, python, go, quarkus", http.StatusBadRequest) + jsonError(w, "invalid runtime: must be one of node, python, go, quarkus", http.StatusBadRequest) return } if !validBranch.MatchString(cfg.Branch) { - http.Error(w, "invalid branch name", http.StatusBadRequest) + jsonError(w, "invalid branch name", http.StatusBadRequest) return } if !validNamespace.MatchString(cfg.Namespace) { - http.Error(w, "invalid namespace: must contain only lowercase alphanumeric characters and hyphens", http.StatusBadRequest) + jsonError(w, "invalid namespace: must contain only lowercase alphanumeric characters and hyphens", http.StatusBadRequest) return } tmpDir, err := os.MkdirTemp("", "func-create-*") if err != nil { - http.Error(w, "failed to create temp dir: "+err.Error(), http.StatusInternalServerError) + jsonError(w, "failed to create temp dir: "+err.Error(), http.StatusInternalServerError) return } defer os.RemoveAll(tmpDir) @@ -160,12 +166,12 @@ func handleFuncCreate(w http.ResponseWriter, r *http.Request) { Template: "http", }) if err != nil { - http.Error(w, "failed to initialize function: "+err.Error(), http.StatusInternalServerError) + jsonError(w, "failed to initialize function: "+err.Error(), http.StatusInternalServerError) return } if err := generateCIWorkflow(root, cfg.Branch, cfg.Registry); err != nil { - http.Error(w, "failed to generate CI workflow: "+err.Error(), http.StatusInternalServerError) + jsonError(w, "failed to generate CI workflow: "+err.Error(), http.StatusInternalServerError) return } @@ -205,7 +211,7 @@ func handleFuncCreate(w http.ResponseWriter, r *http.Request) { return nil }) if err != nil { - http.Error(w, "failed to read generated files: "+err.Error(), http.StatusInternalServerError) + jsonError(w, "failed to read generated files: "+err.Error(), http.StatusInternalServerError) return }