errors.go 4.8 KB

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