package httpapi import ( "encoding/json" "log/slog" "net/http" ) // Problem is an RFC 9457 error body. // // Detail NEVER carries engine text. The engine's own detail strings read like "CJK leak in the ru // output: 第一节" — pipeline vocabulary that must not cross this seam (contract §2.12). What goes // here is a product phrase or nothing. type Problem struct { Type string `json:"type"` Title string `json:"title"` Status int `json:"status"` Detail string `json:"detail,omitempty"` } // WriteProblem renders an error response. func WriteProblem(w http.ResponseWriter, status int, title, detail string) { w.Header().Set("Content-Type", "application/problem+json") w.WriteHeader(status) if err := json.NewEncoder(w).Encode(Problem{Type: "about:blank", Title: title, Status: status, Detail: detail}); err != nil { slog.Debug("problem body not delivered", "err", err) // the client went away mid-write } } // ProblemHandler is a static problem response, for the middleware that must be handed a denier. func ProblemHandler(status int, title string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { WriteProblem(w, status, title, "") }) }