1
0
Fork 1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-06-02 16:48:16 -04:00
pkg-proxy/internal/server/errors.go
Andrew Nesbitt 8d2740624f
Structured JSON error responses for API endpoints (#110)
* Structured JSON error responses for API endpoints

API handlers returned errors via http.Error (text/plain) with ad-hoc
strings, while the mirror API used a different {"error": "..."} shape
and leaked internal err.Error() text to clients.

Add ErrorResponse{Code, Message} with stable codes (BAD_REQUEST,
NOT_FOUND, UPSTREAM_ERROR, INTERNAL_ERROR) and writeError/badRequest/
notFound/internalError helpers. Convert all JSON API handlers in
api.go, browse.go, mirror_api.go and the /stats endpoint. Enrichment
failures now report 502 UPSTREAM_ERROR rather than 500.

Protocol handlers in internal/handler/ are deliberately unchanged
since npm/pip/cargo clients expect their own response formats, not
JSON. HTML page handlers in server.go also keep text/plain.

Swagger @Failure annotations updated and docs regenerated.

Fixes #76

* Convert validatePackagePath errors to JSON in API handlers
2026-05-03 09:42:03 +01:00

42 lines
1.3 KiB
Go

package server
import (
"encoding/json"
"net/http"
)
// Error codes returned in API error responses. These are stable identifiers
// that clients can match on; the message text is for humans and may change.
const (
ErrCodeBadRequest = "BAD_REQUEST"
ErrCodeNotFound = "NOT_FOUND"
ErrCodeUpstream = "UPSTREAM_ERROR"
ErrCodeInternal = "INTERNAL_ERROR"
)
// ErrorResponse is the JSON body returned for API errors.
type ErrorResponse struct {
Code string `json:"code"`
Message string `json:"message"`
}
// writeError sends a JSON error response with the given status, code and
// user-facing message. Internal error details should be logged separately
// by the caller, never passed as the message.
func writeError(w http.ResponseWriter, status int, code, message string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(ErrorResponse{Code: code, Message: message})
}
func badRequest(w http.ResponseWriter, message string) {
writeError(w, http.StatusBadRequest, ErrCodeBadRequest, message)
}
func notFound(w http.ResponseWriter, message string) {
writeError(w, http.StatusNotFound, ErrCodeNotFound, message)
}
func internalError(w http.ResponseWriter, message string) {
writeError(w, http.StatusInternalServerError, ErrCodeInternal, message)
}