// Package server provides HTTP server functionality package server import ( "errors" "fmt" "net/http" ) // Common server error types var ( // ErrInvalidConfig indicates missing or invalid server configuration ErrInvalidConfig = errors.New("invalid server configuration") // ErrServerStartFailed indicates failure to start the server ErrServerStartFailed = errors.New("failed to start server") // ErrUnauthorizedOrigin indicates a request from an unauthorized origin ErrUnauthorizedOrigin = errors.New("unauthorized origin") // ErrRouteSetupFailed indicates failure to set up routes ErrRouteSetupFailed = errors.New("failed to set up routes") // ErrHandlerNotFound indicates a missing handler ErrHandlerNotFound = errors.New("handler not found") // ErrPanicRecovered indicates a recovered panic ErrPanicRecovered = errors.New("panic recovered") // ErrMiddlewareError indicates a middleware error ErrMiddlewareError = errors.New("middleware error") // HTTP error types ErrBadRequest = errors.New("bad request") ErrUnauthorized = errors.New("unauthorized") ErrValidationFailed = errors.New("validation failed") ErrForbidden = errors.New("forbidden") ErrNotFound = errors.New("not found") ErrMethodNotAllowed = errors.New("method not allowed") ErrInternalServer = errors.New("internal server error") ErrServiceUnavailable = errors.New("service unavailable") ) // Error represents a server-specific error with detailed context type Error struct { // Op is the operation that failed (e.g., "start", "route", "middleware") Op string // Err is the underlying error Err error // Details contains additional error context Details string // StatusCode is the HTTP status code (if applicable) StatusCode int // Path is the request path (if applicable) Path string // Method is the HTTP method (if applicable) Method string // Origin is the request origin (if applicable) Origin string // RequestID is the request ID (if applicable) RequestID string } // Error returns a string representation of the error func (e *Error) Error() string { msg := fmt.Sprintf("server %s failed", e.Op) if e.StatusCode > 0 { msg = fmt.Sprintf("%s with status %d", msg, e.StatusCode) } if e.Method != "" && e.Path != "" { msg = fmt.Sprintf("%s for %s %s", msg, e.Method, e.Path) } if e.Origin != "" { msg = fmt.Sprintf("%s from origin %s", msg, e.Origin) } if e.RequestID != "" { msg = fmt.Sprintf("%s (request ID: %s)", msg, e.RequestID) } if e.Details != "" { msg = fmt.Sprintf("%s: %s", msg, e.Details) } if e.Err != nil { msg = fmt.Sprintf("%s: %v", msg, e.Err) } return msg } // Unwrap returns the underlying error func (e *Error) Unwrap() error { return e.Err } // Is reports whether target matches this error func (e *Error) Is(target error) bool { return errors.Is(e.Err, target) } // NewError creates a new server error func NewError(op string, err error, details string) *Error { return &Error{ Op: op, Err: err, Details: details, } } // NewRequestError creates a new server error with request context func NewRequestError(op string, method string, path string, statusCode int, err error, details string) *Error { return &Error{ Op: op, Method: method, Path: path, StatusCode: statusCode, Err: err, Details: details, } } // NewMiddlewareError creates a new middleware error func NewMiddlewareError(op string, requestID string, err error, details string) *Error { return &Error{ Op: op, RequestID: requestID, Err: err, Details: details, } } // NewCORSError creates a new CORS error func NewCORSError(origin string, err error, details string) *Error { return &Error{ Op: "cors", Origin: origin, Err: err, Details: details, } } // StatusCode returns the appropriate HTTP status code for the error func StatusCode(err error) int { var e *Error if errors.As(err, &e) && e.StatusCode > 0 { return e.StatusCode } switch { case errors.Is(err, ErrBadRequest): return http.StatusBadRequest case errors.Is(err, ErrUnauthorized): return http.StatusUnauthorized case errors.Is(err, ErrForbidden): return http.StatusForbidden case errors.Is(err, ErrNotFound): return http.StatusNotFound case errors.Is(err, ErrMethodNotAllowed): return http.StatusMethodNotAllowed case errors.Is(err, ErrUnauthorizedOrigin): return http.StatusForbidden case errors.Is(err, ErrServiceUnavailable): return http.StatusServiceUnavailable default: return http.StatusInternalServerError } } // IsClientError returns true if the error represents a client error (4xx) func IsClientError(err error) bool { code := StatusCode(err) return code >= 400 && code < 500 } // IsServerError returns true if the error represents a server error (5xx) func IsServerError(err error) bool { code := StatusCode(err) return code >= 500 }