123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- // 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")
- 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
- }
|