Documentation
¶
Overview ¶
Package httpx is a small fluent HTTP client on top of net/http, with retries, request tracing and typed response helpers.
Index ¶
- Constants
- Variables
- func IsTimeout(err error) bool
- func ToBytes(resp *Response, err error) ([]byte, error)
- func ToJSON[T any](resp *Response, err error) (T, error)
- func ToString(resp *Response, err error) (string, error)
- type APIKeyAuth
- type APIKeyQueryAuth
- type Auth
- type BasicAuth
- type BearerAuth
- type Client
- func (c *Client) Close()
- func (c *Client) DELETE(url string) *RequestBuilder
- func (c *Client) GET(url string) *RequestBuilder
- func (c *Client) HEAD(url string) *RequestBuilder
- func (c *Client) OPTIONS(url string) *RequestBuilder
- func (c *Client) PATCH(url string) *RequestBuilder
- func (c *Client) POST(url string) *RequestBuilder
- func (c *Client) PUT(url string) *RequestBuilder
- func (c *Client) QUERY(url string) *RequestBuilder
- type HTTPError
- type Logger
- type Middleware
- type Option
- func WithAuth(auth Auth) Option
- func WithBaseURL(baseURL string) Option
- func WithCheckRedirect(fn func(req *http.Request, via []*http.Request) error) Option
- func WithClientName(value string) Option
- func WithCookieJar(jar http.CookieJar) Option
- func WithHTTPClient(client *http.Client) Option
- func WithHeader(key, value string) Option
- func WithLogger(logger Logger) Option
- func WithMaxResponseBytes(n int64) Option
- func WithMiddleware(m ...Middleware) Option
- func WithPoolConfig(cfg PoolConfig) Option
- func WithProxy(proxy func(*http.Request) (*url.URL, error)) Option
- func WithQueryParam(key, value string) Option
- func WithRequestHook(h RequestHook) Option
- func WithResponseHook(h ResponseHook) Option
- func WithRetryPolicy(p RetryPolicy) Option
- func WithTLSConfig(cfg *tls.Config) Option
- func WithTimeout(timeout time.Duration) Option
- func WithTracer(tracer Tracer) Option
- func WithTransport(transport http.RoundTripper) Option
- type PoolConfig
- type RequestBuilder
- func (rb *RequestBuilder) Auth(auth Auth) *RequestBuilder
- func (rb *RequestBuilder) Body(body io.Reader) *RequestBuilder
- func (rb *RequestBuilder) Debug() *RequestBuilder
- func (rb *RequestBuilder) Do(ctx context.Context) (*Response, error)
- func (rb *RequestBuilder) ErrorInto(v any) *RequestBuilder
- func (rb *RequestBuilder) Field(key, value string) *RequestBuilder
- func (rb *RequestBuilder) Fields(fields url.Values) *RequestBuilder
- func (rb *RequestBuilder) File(fieldName, filePath string) *RequestBuilder
- func (rb *RequestBuilder) FileReader(fieldName string, r io.Reader, filename string, contentType ...string) *RequestBuilder
- func (rb *RequestBuilder) Form(fields map[string]string) *RequestBuilder
- func (rb *RequestBuilder) FormValues(values url.Values) *RequestBuilder
- func (rb *RequestBuilder) Header(key, value string) *RequestBuilder
- func (rb *RequestBuilder) Headers(headers map[string]string) *RequestBuilder
- func (rb *RequestBuilder) IdempotencyKey(key string) *RequestBuilder
- func (rb *RequestBuilder) JSON(v any) *RequestBuilder
- func (rb *RequestBuilder) PathParam(name, value string) *RequestBuilder
- func (rb *RequestBuilder) QueryParam(key, value string) *RequestBuilder
- func (rb *RequestBuilder) QueryParams(params map[string]string) *RequestBuilder
- func (rb *RequestBuilder) Retryable() *RequestBuilder
- func (rb *RequestBuilder) Timeout(timeout time.Duration) *RequestBuilder
- func (rb *RequestBuilder) ToCURL(ctx context.Context) (string, error)
- func (rb *RequestBuilder) ToText(ctx context.Context) (string, error)
- type RequestHook
- type Response
- type ResponseHook
- type RetryPolicy
- type TraceInfo
- type Tracer
Constants ¶
const Version = "v1.0.3"
Variables ¶
var ErrEmptyBody = errors.New("httpx: empty response body")
ErrEmptyBody is returned by ToJSON for a successful response with no body (a 204, say).
Functions ¶
Types ¶
type APIKeyAuth ¶
APIKeyAuth sends an API key in a header such as X-API-Key.
type APIKeyQueryAuth ¶
APIKeyQueryAuth sends an API key as a query parameter. Prefer the header variant when the server supports it: httpx keeps query strings out of its logs and errors, but proxies and servers may still record them.
type Auth ¶
Auth adds credentials to outgoing requests.
func NewAPIKeyAuth ¶
func NewAPIKeyQueryAuth ¶
func NewBasicAuth ¶
func NewBearerAuth ¶
type BasicAuth ¶
type BasicAuth struct{ Username, Password string }
BasicAuth sends HTTP Basic credentials.
type BearerAuth ¶
type BearerAuth struct{ Token string }
BearerAuth sends an Authorization: Bearer header.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is safe for concurrent use once built with New.
func (*Client) DELETE ¶
func (c *Client) DELETE(url string) *RequestBuilder
func (*Client) GET ¶
func (c *Client) GET(url string) *RequestBuilder
func (*Client) HEAD ¶
func (c *Client) HEAD(url string) *RequestBuilder
func (*Client) OPTIONS ¶
func (c *Client) OPTIONS(url string) *RequestBuilder
func (*Client) PATCH ¶
func (c *Client) PATCH(url string) *RequestBuilder
func (*Client) POST ¶
func (c *Client) POST(url string) *RequestBuilder
func (*Client) PUT ¶
func (c *Client) PUT(url string) *RequestBuilder
func (*Client) QUERY ¶
func (c *Client) QUERY(url string) *RequestBuilder
QUERY is the safe, idempotent QUERY method, normally with the query in the body. The server and any proxies in between have to support it.
type HTTPError ¶
type HTTPError struct {
Method string
URL string
StatusCode int
Status string
Header http.Header
Body string
// Decoded is true when the body was decoded into the value given to ErrorInto.
// Only JSON responses are decoded (see ErrorInto).
Decoded bool
}
HTTPError is what you get for a non-2xx response. Body is cut off at about 4 KiB and URL has no query string.
type Logger ¶
type Logger interface {
Debug(ctx context.Context, msg string, keysAndValues ...any)
Info(ctx context.Context, msg string, keysAndValues ...any)
Error(ctx context.Context, msg string, keysAndValues ...any)
}
Logger is an optional structured logger.
type Middleware ¶
type Middleware func(http.RoundTripper) http.RoundTripper
Middleware wraps a RoundTripper. The first middleware given is the outermost.
type Option ¶
type Option func(*Client)
Option configures a Client. Options only record what was asked for and New builds the http.Client once at the end, so their order doesn't matter.
func WithBaseURL ¶
WithBaseURL sets the base for relative paths. Its own path is kept, so "https://x.com/v1" plus "/users" gives "https://x.com/v1/users".
func WithCheckRedirect ¶
WithCheckRedirect sets the redirect policy. Return http.ErrUseLastResponse to stop following.
func WithClientName ¶
WithClientName sets the X-Client-Name header.
func WithCookieJar ¶
func WithHTTPClient ¶
WithHTTPClient builds on a copy of client, the original isn't modified. Its Timeout is the default request timeout unless WithTimeout is also set.
func WithHeader ¶
func WithLogger ¶
func WithMaxResponseBytes ¶
WithMaxResponseBytes caps what ToJSON, ToBytes and ToString will read. A body you read yourself from Do is not limited.
func WithMiddleware ¶
func WithMiddleware(m ...Middleware) Option
WithMiddleware adds RoundTripper middlewares (metrics, rate limiting, ...).
func WithPoolConfig ¶
func WithPoolConfig(cfg PoolConfig) Option
WithPoolConfig sets up connection pooling. Needs an *http.Transport underneath.
func WithQueryParam ¶
func WithRequestHook ¶
func WithRequestHook(h RequestHook) Option
func WithResponseHook ¶
func WithResponseHook(h ResponseHook) Option
func WithRetryPolicy ¶
func WithRetryPolicy(p RetryPolicy) Option
WithRetryPolicy turns on retries. Only idempotent methods with replayable bodies are retried.
func WithTLSConfig ¶
WithTLSConfig sets the TLS config, e.g. custom CAs or client certs for mTLS. Needs an *http.Transport underneath.
func WithTimeout ¶
WithTimeout sets the default timeout for a request attempt. Zero disables it.
func WithTracer ¶
func WithTransport ¶
func WithTransport(transport http.RoundTripper) Option
type PoolConfig ¶
type PoolConfig struct {
MaxIdleConns int
MaxIdleConnsPerHost int
MaxConnsPerHost int
IdleConnTimeout time.Duration
TLSHandshakeTimeout time.Duration
ResponseHeaderTimeout time.Duration
}
PoolConfig tunes the connection pool of the default transport. Zero values leave the transport's own setting alone.
type RequestBuilder ¶
type RequestBuilder struct {
// contains filtered or unexported fields
}
RequestBuilder builds a single request. Don't share one between goroutines that send it at the same time.
func (*RequestBuilder) Auth ¶
func (rb *RequestBuilder) Auth(auth Auth) *RequestBuilder
Auth overrides the client's auth for this request.
func (*RequestBuilder) Body ¶
func (rb *RequestBuilder) Body(body io.Reader) *RequestBuilder
Body sets a raw body. For retries it has to be replayable, which *bytes.Buffer, *bytes.Reader and *strings.Reader are.
func (*RequestBuilder) Debug ¶
func (rb *RequestBuilder) Debug() *RequestBuilder
Debug prints the trace once the headers arrive or the request fails, to the logger if there is one and to stderr otherwise.
func (*RequestBuilder) Do ¶ added in v1.0.1
func (rb *RequestBuilder) Do(ctx context.Context) (*Response, error)
Do sends the request. The caller has to close the response body.
The timeout applies to each attempt on its own, so a 10s timeout gives every retry a fresh 10s, and on the last attempt it keeps running until the body is closed. ctx bounds the whole call, backoff waits included.
func (*RequestBuilder) ErrorInto ¶ added in v1.0.3
func (rb *RequestBuilder) ErrorInto(v any) *RequestBuilder
ErrorInto sets where the JSON body of a non-2xx response is decoded, so ToJSON, ToBytes and ToString fill it in and still return an *HTTPError:
var apiErr APIError todo, err := httpx.ToJSON[Todo](client.GET(u).ErrorInto(&apiErr).Do(ctx))
Only responses with a JSON Content-Type (application/json or a +json type) are decoded; a missing Content-Type counts as JSON. HTML, plain text and other types are left alone and stay available in HTTPError.Body.
v has to be a non-nil pointer. With it set, the whole error body is read (up to the client's max response size) for decoding; HTTPError.Body still holds only a short excerpt, and HTTPError.Decoded says whether decoding worked.
func (*RequestBuilder) Field ¶
func (rb *RequestBuilder) Field(key, value string) *RequestBuilder
Field adds a multipart text field.
func (*RequestBuilder) Fields ¶
func (rb *RequestBuilder) Fields(fields url.Values) *RequestBuilder
Fields adds several multipart text fields.
func (*RequestBuilder) File ¶
func (rb *RequestBuilder) File(fieldName, filePath string) *RequestBuilder
File attaches a local file to a multipart upload. Call it as often as you like, even with the same field name; parts go out in call order.
func (*RequestBuilder) FileReader ¶
func (rb *RequestBuilder) FileReader(fieldName string, r io.Reader, filename string, contentType ...string) *RequestBuilder
FileReader attaches the content of r as a multipart file part. The content type is optional and falls back to the filename's extension.
r is read once, when Do builds the body, and the result is buffered in memory so retries can replay it. You still own r and should close it. Since r is used up, sending the same builder twice needs a fresh reader.
func (*RequestBuilder) Form ¶
func (rb *RequestBuilder) Form(fields map[string]string) *RequestBuilder
Form sends URL-encoded form data, one value per key.
func (*RequestBuilder) FormValues ¶
func (rb *RequestBuilder) FormValues(values url.Values) *RequestBuilder
FormValues is Form with several values allowed per key.
func (*RequestBuilder) Header ¶
func (rb *RequestBuilder) Header(key, value string) *RequestBuilder
func (*RequestBuilder) Headers ¶
func (rb *RequestBuilder) Headers(headers map[string]string) *RequestBuilder
func (*RequestBuilder) IdempotencyKey ¶
func (rb *RequestBuilder) IdempotencyKey(key string) *RequestBuilder
IdempotencyKey sets the Idempotency-Key header and marks the request retryable, so POST and PATCH can be retried against servers that honor it.
func (*RequestBuilder) JSON ¶
func (rb *RequestBuilder) JSON(v any) *RequestBuilder
JSON encodes v as the request body without escaping <, > and &. An encoding error is returned from Do.
func (*RequestBuilder) PathParam ¶
func (rb *RequestBuilder) PathParam(name, value string) *RequestBuilder
PathParam fills in "{name}" in the URL with the escaped value, e.g. "/users/{id}".
func (*RequestBuilder) QueryParam ¶
func (rb *RequestBuilder) QueryParam(key, value string) *RequestBuilder
QueryParam adds a query parameter.
func (*RequestBuilder) QueryParams ¶
func (rb *RequestBuilder) QueryParams(params map[string]string) *RequestBuilder
QueryParams sets query parameters, replacing existing values for the same keys.
func (*RequestBuilder) Retryable ¶
func (rb *RequestBuilder) Retryable() *RequestBuilder
Retryable lets a non-idempotent request (a POST, say) use the retry policy. Only do that when repeating it is harmless, ideally with an idempotency key, and the body can be replayed.
func (*RequestBuilder) Timeout ¶
func (rb *RequestBuilder) Timeout(timeout time.Duration) *RequestBuilder
Timeout overrides the client timeout for this request. It's per attempt; the context passed to Do still limits the whole call.
type RequestHook ¶
RequestHook runs right before every attempt. It must be safe for concurrent use.
type Response ¶
Response wraps http.Response.
func (*Response) Close ¶
Close drains up to 4 KiB so the connection can be reused, then closes the body. The cap stops a huge response from blocking Close.
type ResponseHook ¶
ResponseHook runs after the headers of every attempt arrive. It must be safe for concurrent use.
type RetryPolicy ¶
type RetryPolicy struct {
MaxAttempts int
InitialBackoff time.Duration
MaxBackoff time.Duration
RetryableStatusCodes []int
RetryNetworkErrors bool
Jitter bool
RespectRetryAfter bool
}
RetryPolicy controls retries. MaxAttempts counts the first try, so anything below 2 means no retries. With Jitter each backoff is a random value between zero and the exponential cap. With RespectRetryAfter, a server asking for more than MaxBackoff (when set) is not waited for: the response is handed back to the caller instead.
func AggressiveRetryPolicy ¶ added in v1.0.2
func AggressiveRetryPolicy() RetryPolicy
AggressiveRetryPolicy retries more often, and on 500s too.
func BackgroundRetryPolicy ¶ added in v1.0.2
func BackgroundRetryPolicy() RetryPolicy
BackgroundRetryPolicy is for batch jobs where nobody is waiting on the result.
func FastRetryPolicy ¶ added in v1.0.2
func FastRetryPolicy() RetryPolicy
FastRetryPolicy is meant for quick internal calls.
func NoRetryPolicy ¶ added in v1.0.2
func NoRetryPolicy() RetryPolicy
NoRetryPolicy turns retries off.
func RateLimitRetryPolicy ¶ added in v1.0.2
func RateLimitRetryPolicy() RetryPolicy
RateLimitRetryPolicy is tuned for 429s.
func ResilientRetryPolicy ¶ added in v1.0.2
func ResilientRetryPolicy() RetryPolicy
ResilientRetryPolicy is for flaky third-party APIs.
func StandardRetryPolicy ¶
func StandardRetryPolicy() RetryPolicy
StandardRetryPolicy is a sane default: three attempts, network errors plus 429/502/503/504, jittered backoff capped at 2s, and Retry-After honored.
type TraceInfo ¶
type TraceInfo struct {
Method string
URL string
Path string
StatusCode int
DNSLookup time.Duration
ConnTime time.Duration
TCPConnTime time.Duration
TLSHandshake time.Duration
ServerTime time.Duration
ResponseTime time.Duration
TotalTime time.Duration
IsConnReused bool
IsConnWasIdle bool
ConnIdleTime time.Duration
RequestAttempt int
RemoteAddr string
// contains filtered or unexported fields
}
TraceInfo holds timings collected through net/http/httptrace. They're best-effort: some stay zero on a reused connection, behind a proxy, or when the transport doesn't fire the hook. TotalTime stops when the response headers arrive. URL never carries the query string since it may hold secrets.