errors.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Package server provides HTTP server functionality
  2. package server
  3. import (
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. )
  8. // Common server error types
  9. var (
  10. // ErrInvalidConfig indicates missing or invalid server configuration
  11. ErrInvalidConfig = errors.New("invalid server configuration")
  12. // ErrServerStartFailed indicates failure to start the server
  13. ErrServerStartFailed = errors.New("failed to start server")
  14. // ErrUnauthorizedOrigin indicates a request from an unauthorized origin
  15. ErrUnauthorizedOrigin = errors.New("unauthorized origin")
  16. // ErrRouteSetupFailed indicates failure to set up routes
  17. ErrRouteSetupFailed = errors.New("failed to set up routes")
  18. // ErrHandlerNotFound indicates a missing handler
  19. ErrHandlerNotFound = errors.New("handler not found")
  20. // ErrPanicRecovered indicates a recovered panic
  21. ErrPanicRecovered = errors.New("panic recovered")
  22. // ErrMiddlewareError indicates a middleware error
  23. ErrMiddlewareError = errors.New("middleware error")
  24. // HTTP error types
  25. ErrBadRequest = errors.New("bad request")
  26. ErrUnauthorized = errors.New("unauthorized")
  27. ErrForbidden = errors.New("forbidden")
  28. ErrNotFound = errors.New("not found")
  29. ErrMethodNotAllowed = errors.New("method not allowed")
  30. ErrInternalServer = errors.New("internal server error")
  31. ErrServiceUnavailable = errors.New("service unavailable")
  32. )
  33. // Error represents a server-specific error with detailed context
  34. type Error struct {
  35. // Op is the operation that failed (e.g., "start", "route", "middleware")
  36. Op string
  37. // Err is the underlying error
  38. Err error
  39. // Details contains additional error context
  40. Details string
  41. // StatusCode is the HTTP status code (if applicable)
  42. StatusCode int
  43. // Path is the request path (if applicable)
  44. Path string
  45. // Method is the HTTP method (if applicable)
  46. Method string
  47. // Origin is the request origin (if applicable)
  48. Origin string
  49. // RequestID is the request ID (if applicable)
  50. RequestID string
  51. }
  52. // Error returns a string representation of the error
  53. func (e *Error) Error() string {
  54. msg := fmt.Sprintf("server %s failed", e.Op)
  55. if e.StatusCode > 0 {
  56. msg = fmt.Sprintf("%s with status %d", msg, e.StatusCode)
  57. }
  58. if e.Method != "" && e.Path != "" {
  59. msg = fmt.Sprintf("%s for %s %s", msg, e.Method, e.Path)
  60. }
  61. if e.Origin != "" {
  62. msg = fmt.Sprintf("%s from origin %s", msg, e.Origin)
  63. }
  64. if e.RequestID != "" {
  65. msg = fmt.Sprintf("%s (request ID: %s)", msg, e.RequestID)
  66. }
  67. if e.Details != "" {
  68. msg = fmt.Sprintf("%s: %s", msg, e.Details)
  69. }
  70. if e.Err != nil {
  71. msg = fmt.Sprintf("%s: %v", msg, e.Err)
  72. }
  73. return msg
  74. }
  75. // Unwrap returns the underlying error
  76. func (e *Error) Unwrap() error {
  77. return e.Err
  78. }
  79. // Is reports whether target matches this error
  80. func (e *Error) Is(target error) bool {
  81. return errors.Is(e.Err, target)
  82. }
  83. // NewError creates a new server error
  84. func NewError(op string, err error, details string) *Error {
  85. return &Error{
  86. Op: op,
  87. Err: err,
  88. Details: details,
  89. }
  90. }
  91. // NewRequestError creates a new server error with request context
  92. func NewRequestError(op string, method string, path string, statusCode int, err error, details string) *Error {
  93. return &Error{
  94. Op: op,
  95. Method: method,
  96. Path: path,
  97. StatusCode: statusCode,
  98. Err: err,
  99. Details: details,
  100. }
  101. }
  102. // NewMiddlewareError creates a new middleware error
  103. func NewMiddlewareError(op string, requestID string, err error, details string) *Error {
  104. return &Error{
  105. Op: op,
  106. RequestID: requestID,
  107. Err: err,
  108. Details: details,
  109. }
  110. }
  111. // NewCORSError creates a new CORS error
  112. func NewCORSError(origin string, err error, details string) *Error {
  113. return &Error{
  114. Op: "cors",
  115. Origin: origin,
  116. Err: err,
  117. Details: details,
  118. }
  119. }
  120. // StatusCode returns the appropriate HTTP status code for the error
  121. func StatusCode(err error) int {
  122. var e *Error
  123. if errors.As(err, &e) && e.StatusCode > 0 {
  124. return e.StatusCode
  125. }
  126. switch {
  127. case errors.Is(err, ErrBadRequest):
  128. return http.StatusBadRequest
  129. case errors.Is(err, ErrUnauthorized):
  130. return http.StatusUnauthorized
  131. case errors.Is(err, ErrForbidden):
  132. return http.StatusForbidden
  133. case errors.Is(err, ErrNotFound):
  134. return http.StatusNotFound
  135. case errors.Is(err, ErrMethodNotAllowed):
  136. return http.StatusMethodNotAllowed
  137. case errors.Is(err, ErrUnauthorizedOrigin):
  138. return http.StatusForbidden
  139. case errors.Is(err, ErrServiceUnavailable):
  140. return http.StatusServiceUnavailable
  141. default:
  142. return http.StatusInternalServerError
  143. }
  144. }
  145. // IsClientError returns true if the error represents a client error (4xx)
  146. func IsClientError(err error) bool {
  147. code := StatusCode(err)
  148. return code >= 400 && code < 500
  149. }
  150. // IsServerError returns true if the error represents a server error (5xx)
  151. func IsServerError(err error) bool {
  152. code := StatusCode(err)
  153. return code >= 500
  154. }