httpclient

package module
v0.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 1, 2026 License: MIT Imports: 16 Imported by: 0

README

httpclient

Configurable HTTP client with built-in authentication, TLS, resilience (retry, circuit breaker, rate limiting), and streaming support. Includes a typed REST client for JSON APIs.

Install

go get github.com/kbukum/gokit/httpclient

Quick Start

Base HTTP Client
client, err := httpclient.New(httpclient.Config{
    BaseURL: "https://api.example.com",
    Auth:    httpclient.BearerAuth("my-token"),
})

resp, err := client.Do(ctx, httpclient.Request{
    Method: http.MethodGet,
    Path:   "/users/123",
})
fmt.Println(resp.StatusCode, string(resp.Body))
REST Client (JSON)
import "github.com/kbukum/gokit/httpclient/rest"

client, err := rest.New(httpclient.Config{
    BaseURL: "https://api.example.com",
    Auth:    httpclient.BearerAuth("token"),
})

// Typed GET
user, err := rest.Get[User](ctx, client, "/users/123")
fmt.Println(user.Data.Name)

// Typed POST
created, err := rest.Post[User](ctx, client, "/users", CreateUserRequest{
    Name: "Alice",
})
With Resilience
client, err := httpclient.New(httpclient.Config{
    BaseURL:        "https://api.example.com",
    Retry:          httpclient.DefaultRetryConfig(),
    CircuitBreaker: httpclient.DefaultCircuitBreakerConfig("my-api"),
})
// Retry on transient errors (5xx, timeouts, connection failures)
// Circuit breaker opens after repeated failures
SSE Streaming
stream, err := client.DoStream(ctx, httpclient.Request{
    Method: http.MethodGet,
    Path:   "/events",
})
defer stream.Close()

for {
    event, err := stream.SSE.Next()
    if err == io.EOF {
        break
    }
    fmt.Println(event.Event, event.Data)
}

Key Types & Functions

Name Description
Client Base HTTP client with auth, TLS, resilience
Config Client configuration (BaseURL, Timeout, Auth, TLS, Retry, CB, RateLimiter)
Request / Response HTTP request and response types
StreamResponse Streaming response with SSE reader
rest.Client JSON-focused REST client wrapping base client
rest.Get[T] / Post[T] / Put[T] / Patch[T] / Delete[T] Generic typed REST methods
sse.Reader Reusable Server-Sent Events parser
BearerAuth() / BasicAuth() / APIKeyAuth() / CustomAuth() Auth configuration helpers
DefaultRetryConfig() / DefaultCircuitBreakerConfig() Sensible resilience defaults
IsTimeout() / IsAuth() / IsNotFound() / IsRetryable() Error classification helpers

Authentication

// Bearer token
httpclient.BearerAuth("token")

// Basic auth
httpclient.BasicAuth("user", "pass")

// API key in header
httpclient.APIKeyAuth("secret")
httpclient.APIKeyAuthHeader("secret", "X-Custom-Key")

// API key in query parameter
httpclient.APIKeyAuthQuery("secret", "api_key")

// Custom auth
httpclient.CustomAuth(func(req *http.Request) {
    req.Header.Set("X-Signature", sign(req))
})

Error Handling

resp, err := client.Do(ctx, req)
if err != nil {
    switch {
    case httpclient.IsAuth(err):        // 401, 403
    case httpclient.IsNotFound(err):    // 404
    case httpclient.IsRateLimit(err):   // 429
    case httpclient.IsServerError(err): // 5xx
    case httpclient.IsTimeout(err):     // timeouts
    case httpclient.IsConnection(err):  // connection failures
    case httpclient.IsRetryable(err):   // any retryable error
    }
}

TLS

Uses shared security.TLSConfig from gokit core:

client, err := httpclient.New(httpclient.Config{
    BaseURL: "https://internal-api.example.com",
    TLS: &security.TLSConfig{
        CAFile:   "/path/to/ca.pem",
        CertFile: "/path/to/client-cert.pem",
        KeyFile:  "/path/to/client-key.pem",
    },
})

⬅ Back to main README

Documentation

Overview

Package httpclient provides a configurable HTTP adapter with built-in authentication, TLS, resilience (retry, circuit breaker, rate limiting), and streaming support.

The Adapter is both a full-capability HTTP client and a provider.RequestResponse implementation, so it can be used standalone or composed via the provider framework (WithResilience, Manager, Registry, etc.).

Basic Usage

adapter, _ := httpclient.New(httpclient.Config{
    Name:    "my-api",
    BaseURL: "https://api.example.com",
    Timeout: 30 * time.Second,
    Auth:    httpclient.BearerAuth("my-token"),
})

resp, err := adapter.Do(ctx, httpclient.Request{
    Method: http.MethodGet,
    Path:   "/users/123",
})

As a Provider

// The adapter IS a provider — no wrapper needed.
var p provider.RequestResponse[httpclient.Request, *httpclient.Response] = adapter
resilient := provider.WithResilience(adapter, resilienceConfig)

REST Convenience

user, err := httpclient.Get[User](adapter, ctx, "/users/123")
created, err := httpclient.Post[User](adapter, ctx, "/users", body)

With Resilience

adapter, _ := httpclient.New(httpclient.Config{
    BaseURL: "https://api.example.com",
    Retry:   httpclient.DefaultRetryConfig(),
    CircuitBreaker: httpclient.DefaultCircuitBreakerConfig("my-api"),
})

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultCircuitBreakerConfig

func DefaultCircuitBreakerConfig(name string) *resilience.CircuitBreakerConfig

DefaultCircuitBreakerConfig returns a default circuit breaker config.

func DefaultRateLimiterConfig

func DefaultRateLimiterConfig(name string) *resilience.RateLimiterConfig

DefaultRateLimiterConfig returns a default rate limiter config.

func DefaultRetryConfig

func DefaultRetryConfig() *resilience.RetryConfig

DefaultRetryConfig returns a default retry config suitable for HTTP clients.

func IsAuth

func IsAuth(err error) bool

IsAuth checks if an error is an authentication error.

func IsConnection

func IsConnection(err error) bool

IsConnection checks if an error is a connection error.

func IsNotFound

func IsNotFound(err error) bool

IsNotFound checks if an error is a not-found error.

func IsRateLimit

func IsRateLimit(err error) bool

IsRateLimit checks if an error is a rate-limit error.

func IsRetryable

func IsRetryable(err error) bool

IsRetryable checks if an error is retryable.

func IsServerError

func IsServerError(err error) bool

IsServerError checks if an error is a server error.

func IsTimeout

func IsTimeout(err error) bool

IsTimeout checks if an error is a timeout error.

Types

type Adapter added in v0.1.5

type Adapter struct {
	// contains filtered or unexported fields
}

Adapter is a configurable HTTP adapter with built-in auth, TLS, and resilience. It can be used as a simple HTTP client or as a provider.RequestResponse for composition with the provider framework (WithResilience, Manager, Registry, etc.).

func New

func New(cfg Config, opts ...Option) (*Adapter, error)

New creates a new HTTP adapter with the given configuration.

func (*Adapter) Close added in v0.1.5

func (c *Adapter) Close(_ context.Context) error

Close releases resources held by the adapter (implements provider.Closeable).

func (*Adapter) Do added in v0.1.5

func (c *Adapter) Do(ctx context.Context, req Request) (*Response, error)

Do executes an HTTP request and returns the complete response.

func (*Adapter) DoStream added in v0.1.5

func (c *Adapter) DoStream(ctx context.Context, req Request) (*StreamResponse, error)

DoStream executes an HTTP request and returns a streaming response. The caller must close the returned StreamResponse when done. Note: Retry is not applied to streaming requests.

func (*Adapter) Execute added in v0.1.5

func (c *Adapter) Execute(ctx context.Context, req Request) (*Response, error)

Execute sends an HTTP request and returns the response (implements provider.RequestResponse). This is equivalent to Do() but satisfies the provider interface for composition.

func (*Adapter) GetConfig added in v0.1.5

func (c *Adapter) GetConfig() Config

GetConfig returns the adapter's configuration.

func (*Adapter) IsAvailable added in v0.1.5

func (c *Adapter) IsAvailable(_ context.Context) bool

IsAvailable checks if the adapter is ready to handle requests (implements provider.Provider).

func (*Adapter) Name added in v0.1.5

func (c *Adapter) Name() string

Name returns the adapter name (implements provider.Provider).

func (*Adapter) Unwrap added in v0.1.5

func (c *Adapter) Unwrap() *http.Client

Unwrap returns the underlying *http.Client for advanced use cases.

type AuthConfig

type AuthConfig struct {
	// Type is the authentication method.
	Type AuthType
	// Token is the bearer token (AuthBearer).
	Token string
	// Username is the basic auth username (AuthBasic).
	Username string
	// Password is the basic auth password (AuthBasic).
	Password string
	// Key is the API key value (AuthAPIKey).
	Key string
	// In specifies where to place the API key: "header" (default) or "query" (AuthAPIKey).
	In string
	// Name is the header or query parameter name (AuthAPIKey). Defaults to "X-API-Key".
	Name string
	// Apply is a custom function to modify the request (AuthCustom).
	Apply func(*http.Request)
}

AuthConfig configures request authentication.

func APIKeyAuth

func APIKeyAuth(key string) *AuthConfig

APIKeyAuth creates an API key auth config sent via header.

func APIKeyAuthHeader

func APIKeyAuthHeader(key, headerName string) *AuthConfig

APIKeyAuthHeader creates an API key auth config with a custom header name.

func APIKeyAuthQuery

func APIKeyAuthQuery(key, paramName string) *AuthConfig

APIKeyAuthQuery creates an API key auth config sent via query parameter.

func BasicAuth

func BasicAuth(username, password string) *AuthConfig

BasicAuth creates a basic auth config.

func BearerAuth

func BearerAuth(token string) *AuthConfig

BearerAuth creates a bearer token auth config.

func CustomAuth

func CustomAuth(fn func(*http.Request)) *AuthConfig

CustomAuth creates a custom auth config with a request modifier function.

type AuthType

type AuthType int

AuthType identifies the authentication method.

const (
	// AuthNone disables authentication.
	AuthNone AuthType = iota
	// AuthBearer uses Bearer token authentication.
	AuthBearer
	// AuthBasic uses HTTP Basic authentication.
	AuthBasic
	// AuthAPIKey uses API key authentication (header or query parameter).
	AuthAPIKey
	// AuthCustom uses a custom authentication function.
	AuthCustom
)

type Component added in v0.1.5

type Component struct {
	// contains filtered or unexported fields
}

Component wraps an Adapter with lifecycle management. Use this when the HTTP adapter is part of a managed application (e.g., with bootstrap.Start/Stop).

func NewComponent added in v0.1.5

func NewComponent(cfg Config, opts ...Option) *Component

NewComponent creates a new HTTP adapter component. The adapter is created lazily in Start().

func (*Component) Adapter added in v0.1.5

func (c *Component) Adapter() *Adapter

Adapter returns the underlying HTTP adapter. Must be called after Start().

func (*Component) Describe added in v0.1.5

func (c *Component) Describe() component.Description

Describe returns component description for the bootstrap summary.

func (*Component) Health added in v0.1.5

func (c *Component) Health(ctx context.Context) component.Health

Health returns the adapter health status.

func (*Component) Name added in v0.1.5

func (c *Component) Name() string

Name returns the component name.

func (*Component) Start added in v0.1.5

func (c *Component) Start(_ context.Context) error

Start initializes the HTTP adapter.

func (*Component) Stop added in v0.1.5

func (c *Component) Stop(ctx context.Context) error

Stop closes the HTTP adapter and releases resources.

type Config

type Config struct {
	// Name identifies this adapter instance (used by provider.Provider interface).
	Name string `yaml:"name" mapstructure:"name"`

	// BaseURL is the base URL prepended to all request paths.
	BaseURL string `yaml:"base_url" mapstructure:"base_url"`

	// Timeout is the default request timeout. Defaults to 30s.
	Timeout time.Duration `yaml:"timeout" mapstructure:"timeout"`

	// Auth configures default authentication applied to all requests.
	// Individual requests can override this.
	Auth *AuthConfig `yaml:"-" mapstructure:"-"`

	// TLS configures TLS settings for the HTTP transport.
	TLS *security.TLSConfig `yaml:"tls" mapstructure:"tls"`

	// Headers are default headers applied to all requests.
	Headers map[string]string `yaml:"headers" mapstructure:"headers"`

	// Retry configures retry behavior. Nil disables retry.
	Retry *resilience.RetryConfig `yaml:"-" mapstructure:"-"`

	// CircuitBreaker configures circuit breaker behavior. Nil disables it.
	CircuitBreaker *resilience.CircuitBreakerConfig `yaml:"-" mapstructure:"-"`

	// RateLimiter configures rate limiting. Nil disables it.
	RateLimiter *resilience.RateLimiterConfig `yaml:"-" mapstructure:"-"`
}

Config configures the HTTP adapter.

func (*Config) ApplyDefaults

func (c *Config) ApplyDefaults()

ApplyDefaults fills in zero-value fields with sensible defaults.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks that the configuration is valid.

type Error

type Error struct {
	// StatusCode is the HTTP status code (0 for connection-level errors).
	StatusCode int
	// Code classifies the error.
	Code ErrorCode
	// Message describes the error.
	Message string
	// Retryable indicates whether the operation can be retried.
	Retryable bool
	// Body is the original response body (may be nil).
	Body []byte
	// Err is the underlying error.
	Err error
}

Error is a structured HTTP client error with classification.

func ClassifyStatusCode

func ClassifyStatusCode(statusCode int, body []byte) *Error

ClassifyStatusCode converts an HTTP status code into a typed error. Returns nil for 2xx status codes.

func NewAuthError

func NewAuthError(statusCode int, body []byte) *Error

NewAuthError creates an authentication error.

func NewConnectionError

func NewConnectionError(err error) *Error

NewConnectionError creates a connection error.

func NewNotFoundError

func NewNotFoundError(body []byte) *Error

NewNotFoundError creates a not-found error.

func NewRateLimitError

func NewRateLimitError(body []byte) *Error

NewRateLimitError creates a rate-limit error.

func NewServerError

func NewServerError(statusCode int, body []byte) *Error

NewServerError creates a server error.

func NewTimeoutError

func NewTimeoutError(err error) *Error

NewTimeoutError creates a timeout error.

func NewValidationError

func NewValidationError(msg string) *Error

NewValidationError creates a validation error.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the underlying error.

type ErrorCode

type ErrorCode int

ErrorCode classifies HTTP client errors.

const (
	// ErrCodeTimeout indicates a request or connection timeout.
	ErrCodeTimeout ErrorCode = iota
	// ErrCodeConnection indicates a connection failure (refused, DNS, etc).
	ErrCodeConnection
	// ErrCodeAuth indicates an authentication/authorization failure (401/403).
	ErrCodeAuth
	// ErrCodeNotFound indicates the resource was not found (404).
	ErrCodeNotFound
	// ErrCodeRateLimit indicates rate limiting (429).
	ErrCodeRateLimit
	// ErrCodeValidation indicates a client-side validation error (400).
	ErrCodeValidation
	// ErrCodeServer indicates a server-side error (5xx).
	ErrCodeServer
)

func (ErrorCode) String

func (c ErrorCode) String() string

String returns the error code name.

type FileField added in v0.1.5

type FileField struct {
	// FieldName is the form field name (e.g., "file", "audio").
	FieldName string
	// FileName is the file name sent to the server.
	FileName string
	// ContentType is the MIME type (e.g., "audio/wav"). If empty, uses application/octet-stream.
	ContentType string
	// Data is the file content. Used if Reader is nil.
	Data []byte
	// Reader is an alternative to Data for large files (streaming upload).
	Reader io.Reader
}

FileField represents a file to upload in a multipart request.

type MultipartBody added in v0.1.5

type MultipartBody struct {
	// Fields are simple key-value form fields.
	Fields map[string]string
	// Files are file upload fields.
	Files []FileField
}

MultipartBody represents a multipart/form-data request body. Pass this as the Body field of a Request to automatically construct multipart encoding with the correct Content-Type header.

type Option added in v0.1.5

type Option func(*Adapter)

Option configures an Adapter during creation.

type Request

type Request struct {
	// Method is the HTTP method (GET, POST, PUT, PATCH, DELETE, etc).
	Method string
	// Path is appended to the client's BaseURL. Can be a full URL if BaseURL is empty.
	Path string
	// Headers are request-specific headers (merged with client defaults).
	Headers map[string]string
	// Query are URL query parameters.
	Query map[string]string
	// Body is the request body. Accepts io.Reader, []byte, string, or any value
	// that will be JSON-encoded.
	Body any
	// Auth overrides the client-level auth for this request.
	Auth *AuthConfig
}

Request describes an outbound HTTP request.

type RequestOption added in v0.1.5

type RequestOption func(*Request)

RequestOption configures a single request.

func WithHeader added in v0.1.5

func WithHeader(key, value string) RequestOption

WithHeader adds a header to the request.

func WithQueryParam added in v0.1.5

func WithQueryParam(key, value string) RequestOption

WithQueryParam adds a query parameter to the request.

func WithRequestAuth added in v0.1.5

func WithRequestAuth(auth *AuthConfig) RequestOption

WithRequestAuth overrides authentication for the request.

type Response

type Response struct {
	// StatusCode is the HTTP status code.
	StatusCode int
	// Headers are the response headers.
	Headers map[string]string
	// Body is the raw response body.
	Body []byte
}

Response is the result of an HTTP request.

func (*Response) IsError

func (r *Response) IsError() bool

IsError returns true if the status code is 4xx or 5xx.

func (*Response) IsSuccess

func (r *Response) IsSuccess() bool

IsSuccess returns true if the status code is 2xx.

func (*Response) JSON added in v0.1.5

func (r *Response) JSON(v any) error

JSON decodes the response body as JSON into v.

func (*Response) Text added in v0.1.5

func (r *Response) Text() string

Text returns the response body as a string.

type StreamResponse

type StreamResponse struct {
	// StatusCode is the HTTP status code.
	StatusCode int
	// Headers are the response headers.
	Headers map[string]string
	// SSE is the Server-Sent Events reader (for text/event-stream responses).
	SSE sse.Reader
	// Body is the raw streaming body (for non-SSE streams).
	Body io.ReadCloser
	// contains filtered or unexported fields
}

StreamResponse wraps a streaming HTTP response.

func (*StreamResponse) Close

func (r *StreamResponse) Close() error

Close releases all resources associated with the stream.

type TypedResponse added in v0.1.5

type TypedResponse[T any] struct {
	// StatusCode is the HTTP status code.
	StatusCode int
	// Headers are the response headers.
	Headers map[string]string
	// Data is the decoded response body.
	Data T
}

TypedResponse wraps a response with a decoded body of type T.

func Delete added in v0.1.5

func Delete[T any](a *Adapter, ctx context.Context, path string, opts ...RequestOption) (*TypedResponse[T], error)

Delete performs a DELETE request and decodes the JSON response into type T.

func Get added in v0.1.5

func Get[T any](a *Adapter, ctx context.Context, path string, opts ...RequestOption) (*TypedResponse[T], error)

Get performs a GET request and decodes the JSON response into type T.

func Patch added in v0.1.5

func Patch[T any](a *Adapter, ctx context.Context, path string, body any, opts ...RequestOption) (*TypedResponse[T], error)

Patch performs a PATCH request with a JSON body and decodes the response into type T.

func Post added in v0.1.5

func Post[T any](a *Adapter, ctx context.Context, path string, body any, opts ...RequestOption) (*TypedResponse[T], error)

Post performs a POST request with a JSON body and decodes the response into type T.

func Put added in v0.1.5

func Put[T any](a *Adapter, ctx context.Context, path string, body any, opts ...RequestOption) (*TypedResponse[T], error)

Put performs a PUT request with a JSON body and decodes the response into type T.

Directories

Path Synopsis
Package rest provides a JSON-focused REST client built on the HTTP adapter.
Package rest provides a JSON-focused REST client built on the HTTP adapter.
Package sse provides a reusable Server-Sent Events reader.
Package sse provides a reusable Server-Sent Events reader.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL