Add foundation: middleware type, error types, and internal clock

Introduce the core building blocks for the httpx library:
- middleware.Middleware type and Chain() composer
- Error struct with sentinel errors (ErrRetryExhausted, ErrCircuitOpen, ErrNoHealthy)
- internal/clock package with Clock interface and MockClock for deterministic testing
This commit is contained in:
2026-03-20 14:21:43 +03:00
parent f2a4a4fccc
commit 6b1941fce7
4 changed files with 226 additions and 0 deletions

44
error.go Normal file
View File

@@ -0,0 +1,44 @@
package httpx
import (
"errors"
"fmt"
"net/http"
)
// Sentinel errors returned by httpx components.
var (
ErrRetryExhausted = errors.New("httpx: all retry attempts exhausted")
ErrCircuitOpen = errors.New("httpx: circuit breaker is open")
ErrNoHealthy = errors.New("httpx: no healthy endpoints available")
)
// Error provides structured error information for failed HTTP operations.
type Error struct {
// Op is the operation that failed (e.g. "Get", "Do").
Op string
// URL is the originally-requested URL.
URL string
// Endpoint is the resolved endpoint URL (after balancing).
Endpoint string
// StatusCode is the HTTP status code, if a response was received.
StatusCode int
// Retries is the number of retry attempts made.
Retries int
// Err is the underlying error.
Err error
}
func (e *Error) Error() string {
if e.Endpoint != "" && e.Endpoint != e.URL {
return fmt.Sprintf("httpx: %s %s (endpoint %s): %v", e.Op, e.URL, e.Endpoint, e.Err)
}
return fmt.Sprintf("httpx: %s %s: %v", e.Op, e.URL, e.Err)
}
func (e *Error) Unwrap() error { return e.Err }
// ErrorMapper maps an HTTP response to an error. If the response is
// acceptable, the mapper should return nil. Used by Client to convert
// non-successful HTTP responses into Go errors.
type ErrorMapper func(resp *http.Response) error