package handler import ( "encoding/json" "net/http" "github.com/edgeai/gateway/pkg/api" "github.com/google/uuid" ) // ErrorCode constants. const ( ErrAuthFailed = "AUTH_FAILED" ErrPermissionDenied = "PERMISSION_DENIED" ErrPolicyBlocked = "POLICY_BLOCKED" ErrRateLimited = "RATE_LIMITED" ErrQuotaExceeded = "QUOTA_EXCEEDED" ErrQueueFull = "QUEUE_FULL" ErrInvalidRequest = "INVALID_REQUEST" ErrContextTooLarge = "CONTEXT_TOO_LARGE" ErrQueueTimeout = "QUEUE_TIMEOUT" ErrFirstTokenTimeout = "FIRST_TOKEN_TIMEOUT" ErrInferenceTimeout = "INFERENCE_TIMEOUT" ErrRequestCancelled = "REQUEST_CANCELLED" ErrModelUnavailable = "MODEL_UNAVAILABLE" ErrResourceExhausted = "RESOURCE_EXHAUSTED" ErrInternalError = "INTERNAL_ERROR" ) // httpStatusForCode maps error codes to HTTP status codes. var httpStatusForCode = map[string]int{ ErrAuthFailed: http.StatusUnauthorized, ErrPermissionDenied: http.StatusForbidden, ErrPolicyBlocked: http.StatusForbidden, ErrRateLimited: http.StatusTooManyRequests, ErrQuotaExceeded: http.StatusTooManyRequests, ErrQueueFull: http.StatusTooManyRequests, ErrInvalidRequest: http.StatusBadRequest, ErrContextTooLarge: http.StatusBadRequest, ErrQueueTimeout: http.StatusRequestTimeout, ErrFirstTokenTimeout: http.StatusRequestTimeout, ErrInferenceTimeout: http.StatusRequestTimeout, ErrRequestCancelled: http.StatusConflict, ErrModelUnavailable: http.StatusServiceUnavailable, ErrResourceExhausted: http.StatusServiceUnavailable, ErrInternalError: http.StatusInternalServerError, } // GatewayError represents a structured error with code, message, and request ID. type GatewayError struct { Code string Message string RequestID string } func (e *GatewayError) Error() string { return e.Message } // NewGatewayError creates a GatewayError with a generated request ID. func NewGatewayError(code, message string) *GatewayError { return &GatewayError{ Code: code, Message: message, RequestID: uuid.New().String(), } } // NewGatewayErrorWithID creates a GatewayError with an existing request ID. func NewGatewayErrorWithID(code, message, requestID string) *GatewayError { return &GatewayError{ Code: code, Message: message, RequestID: requestID, } } // WriteError writes a structured error response. func WriteError(w http.ResponseWriter, err *GatewayError) { status, ok := httpStatusForCode[err.Code] if !ok { status = http.StatusInternalServerError } w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) resp := api.ErrorResponse{ Error: api.ErrorBody{ Code: err.Code, Message: err.Message, RequestID: err.RequestID, }, } json.NewEncoder(w).Encode(resp) } // WriteJSON writes a JSON response with the given status code. func WriteJSON(w http.ResponseWriter, status int, data any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(data) }