package utils import ( "encoding/json" "fmt" "log/slog" "net/http" ) // APIError represents an API error with status code and message type APIError struct { StatusCode int `json:"statusCode"` Msg any `json:"msg"` } // Error implements the error interface for APIError func (e APIError) Error() string { return fmt.Sprintf("api error: %d", e.StatusCode) } // NewAPIError creates a new APIError with the given status code and error message func NewAPIError(statusCode int, err error) APIError { return APIError{ StatusCode: statusCode, Msg: err.Error(), } } // InvalidRequestData creates an APIError for validation errors with a map of field errors func InvalidRequestData(msg string) APIError { return APIError{ StatusCode: http.StatusUnprocessableEntity, Msg: msg, } } // InvalidJSON creates an APIError for invalid JSON format func InvalidJSON() APIError { return NewAPIError(http.StatusBadRequest, fmt.Errorf("invalid JSON request data")) } // APIResponse represents a standardized API response wrapper type APIResponse struct { Success bool `json:"success"` Data any `json:"data,omitempty"` Error any `json:"error,omitempty"` } // WriteJSON writes the response as JSON with given status code, wrapped in a data object func WriteJSON(w http.ResponseWriter, status int, data any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) response := APIResponse{ Success: status >= 200 && status < 300, } if response.Success { response.Data = data } else { response.Error = data } json.NewEncoder(w).Encode(response) } // APIFunc is the signature for API handler functions type APIFunc func(w http.ResponseWriter, r *http.Request) error // Make wraps an APIFunc and handles errors consistently func Make(h APIFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if err := h(w, r); err != nil { if apiErr, ok := err.(APIError); ok { WriteJSON(w, apiErr.StatusCode, apiErr) } else { errResp := map[string]any{ "statusCode": http.StatusInternalServerError, "msg": "internal server error", } WriteJSON(w, http.StatusInternalServerError, errResp) // You could add logging here slog.Error("HTTP API error", "err", err.Error(), "path", r.URL.Path) } } } }