// Package httputil holds the small HTTP response helpers shared by every API // handler package (docs, suggestions, vocab, …). Keeping them in one place means // JSON encoding and — crucially — error handling behave identically everywhere: // internal errors are logged in full but never leaked to the client. package httputil import ( "encoding/json" "log" "net/http" ) // WriteJSON encodes v as the response body with the given status code. func WriteJSON(w http.ResponseWriter, status int, v any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(v) } // ErrorJSON sends a {"error": msg} body with the given status. The message is // caller-chosen and safe to show the client. func ErrorJSON(w http.ResponseWriter, status int, msg string) { WriteJSON(w, status, map[string]string{"error": msg}) } // BadRequest is the common 400 shorthand. func BadRequest(w http.ResponseWriter, msg string) { ErrorJSON(w, http.StatusBadRequest, msg) } // ServerError logs the real error (with full detail, for the operator) and // returns a generic 500 to the client — raw database/internal errors must never // reach the browser, where they leak schema and implementation details. func ServerError(w http.ResponseWriter, err error) { log.Printf("internal error: %v", err) ErrorJSON(w, http.StatusInternalServerError, "something went wrong") }