87 lines
2.3 KiB
Go
87 lines
2.3 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|
|
}
|