1
0
Fork 1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-06-02 08:38:17 -04:00
pkg-proxy/internal/server/mirror_api.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

61 lines
1.5 KiB
Go

package server
import (
"encoding/json"
"net/http"
"github.com/git-pkgs/proxy/internal/mirror"
"github.com/go-chi/chi/v5"
)
// MirrorAPIHandler handles mirror API requests.
type MirrorAPIHandler struct {
jobs *mirror.JobStore
}
// NewMirrorAPIHandler creates a new mirror API handler.
func NewMirrorAPIHandler(jobs *mirror.JobStore) *MirrorAPIHandler {
return &MirrorAPIHandler{jobs: jobs}
}
// HandleCreate starts a new mirror job.
func (h *MirrorAPIHandler) HandleCreate(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxBodySize)
var req mirror.JobRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
badRequest(w, "invalid request body")
return
}
id, err := h.jobs.Create(req)
if err != nil {
badRequest(w, "invalid mirror job request")
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusAccepted)
writeJSON(w, map[string]string{"id": id})
}
// HandleGet returns the status of a mirror job.
func (h *MirrorAPIHandler) HandleGet(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
job := h.jobs.Get(id)
if job == nil {
notFound(w, "job not found")
return
}
writeJSON(w, job)
}
// HandleCancel cancels a running mirror job.
func (h *MirrorAPIHandler) HandleCancel(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
if h.jobs.Cancel(id) {
writeJSON(w, map[string]string{"status": "canceled"})
} else {
notFound(w, "job not found or not running")
}
}