package api import ( "encoding/json" "log" "net/http" "drivervault/apiserver/internal/pb" ) // writeJSON writes v as a JSON response with the given status code. func writeJSON(w http.ResponseWriter, status int, v any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) if v == nil { return } if err := json.NewEncoder(w).Encode(v); err != nil { log.Printf("writeJSON: %v", err) } } // errorBody is the standard error envelope. type errorBody struct { Error string `json:"error"` } // writeError writes a JSON error response. func writeError(w http.ResponseWriter, status int, msg string) { writeJSON(w, status, errorBody{Error: msg}) } // writeUpstreamDown reports that PocketBase could not be reached at all (a // transport error, as opposed to PocketBase answering with an error status). func writeUpstreamDown(w http.ResponseWriter, err error) { writeJSON(w, http.StatusBadGateway, map[string]any{ "error": "cannot reach PocketBase", "detail": err.Error(), }) } // writePBError maps a PocketBase error from the typed CRUD helpers to an // appropriate HTTP status. func writePBError(w http.ResponseWriter, err error) { if apiErr, ok := err.(*pb.APIError); ok { status := apiErr.Status if status < 400 { status = http.StatusBadGateway } writeError(w, status, apiErr.Body) return } writeError(w, http.StatusBadGateway, err.Error()) } // decodeJSON strictly decodes a request body, rejecting unknown fields. func decodeJSON(r *http.Request, dest any) error { dec := json.NewDecoder(r.Body) dec.DisallowUnknownFields() return dec.Decode(dest) }