{"id":43617938,"url":"https://github.com/slashdevops/httpx","last_synced_at":"2026-03-07T21:05:50.159Z","repository":{"id":333348714,"uuid":"1136806428","full_name":"slashdevops/httpx","owner":"slashdevops","description":"A comprehensive Go package for building and executing HTTP requests with advanced features","archived":false,"fork":false,"pushed_at":"2026-01-19T11:00:39.000Z","size":111,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-04T23:17:50.590Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/slashdevops.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["christiangda"],"liberapay":"christiangda","patreon":"christiangda","custom":["https://paypal.me/slashdevops"]}},"created_at":"2026-01-18T11:51:05.000Z","updated_at":"2026-01-19T10:59:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/slashdevops/httpx","commit_stats":null,"previous_names":["slashdevops/httpx"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/slashdevops/httpx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slashdevops%2Fhttpx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slashdevops%2Fhttpx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slashdevops%2Fhttpx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slashdevops%2Fhttpx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slashdevops","download_url":"https://codeload.github.com/slashdevops/httpx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slashdevops%2Fhttpx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30231491,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T19:01:10.287Z","status":"ssl_error","status_checked_at":"2026-03-07T18:59:58.103Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-04T12:39:23.898Z","updated_at":"2026-03-07T21:05:50.111Z","avatar_url":"https://github.com/slashdevops.png","language":"Go","readme":"# httpx\n\n[![main branch](https://github.com/slashdevops/httpx/actions/workflows/main.yml/badge.svg)](https://github.com/slashdevops/httpx/actions/workflows/main.yml)\n![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/slashdevops/httpx?style=plastic)\n[![Go Reference](https://pkg.go.dev/badge/github.com/slashdevops/httpx.svg)](https://pkg.go.dev/github.com/slashdevops/httpx)\n[![Go Report Card](https://goreportcard.com/badge/github.com/slashdevops/httpx)](https://goreportcard.com/report/github.com/slashdevops/httpx)\n[![license](https://img.shields.io/github/license/slashdevops/httpx.svg)](https://github.com/slashdevops/httpx/blob/main/LICENSE)\n[![Release](https://github.com/slashdevops/httpx/actions/workflows/release.yml/badge.svg)](https://github.com/slashdevops/httpx/actions/workflows/release.yml)\n\nA comprehensive Go package for building and executing HTTP requests with advanced features.\n\n**🚀 Zero Dependencies** - Built entirely using the Go standard library for maximum reliability, security, and minimal maintenance overhead. See [go.mod](go.mod)\n\n## Key Features\n\n- 🔨 **Fluent Request Builder** - Chainable API for constructing HTTP requests\n- 🔄 **Automatic Retry Logic** - Configurable retry strategies with exponential backoff\n- 🎯 **Type-Safe Generic Client** - Go generics for type-safe HTTP responses\n- ✅ **Input Validation** - Comprehensive validation with error accumulation\n- 🔐 **Authentication Support** - Built-in Basic and Bearer token authentication\n- 🌐 **Proxy Support** - HTTP/HTTPS proxy configuration with authentication (supports corporate proxies, authenticated proxies, and custom ports)\n- 📝 **Optional Logging** - slog integration for observability (disabled by default)\n- 📦 **Zero External Dependencies** - Only Go standard library, no third-party packages\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Upgrade](#upgrade)\n- [Quick Start](#quick-start)\n- [Features](#features)\n  - [Request Builder](#request-builder)\n  - [Generic HTTP Client](#generic-http-client)\n  - [Retry Logic](#retry-logic)\n  - [Client Builder](#client-builder)\n  - [Proxy Configuration](#proxy-configuration)\n  - [Logging](#logging)\n- [Examples](#examples)\n- [API Reference](#api-reference)\n- [Best Practices](#best-practices)\n- [Contributing](#contributing)\n\n## Installation\n\n**Requirements:** Go 1.22 or higher\n\n```bash\ngo get github.com/slashdevops/httpx\n```\n\n## Upgrade\n\nTo upgrade to the latest version, run:\n\n```bash\ngo get -u github.com/slashdevops/httpx\n```\n\n## Quick Start\n\n### Simple GET Request\n\n```go\nimport \"github.com/slashdevops/httpx\"\n\n// Build and execute a simple GET request\nreq, err := httpx.NewRequestBuilder(\"https://api.example.com\").\n    WithMethodGET().\n    WithPath(\"/users/123\").\n    WithHeader(\"Accept\", \"application/json\").\n    Build()\n\nif err != nil {\n    log.Fatal(err)\n}\n\n// Use with standard http.Client\nresp, err := http.DefaultClient.Do(req)\n```\n\n### Type-Safe Requests with Generic Client\n\n```go\ntype User struct {\n    ID    int    `json:\"id\"`\n    Name  string `json:\"name\"`\n    Email string `json:\"email\"`\n}\n\n// Create a typed client with configuration\nclient := httpx.NewGenericClient[User](\n    httpx.WithTimeout[User](10 * time.Second),\n    httpx.WithMaxRetries[User](3),\n    httpx.WithRetryStrategy[User](httpx.ExponentialBackoffStrategy),\n)\n\n// Execute typed request\nresponse, err := client.Get(\"https://api.example.com/users/123\")\nif err != nil {\n    log.Fatal(err)\n}\n\n// response.Data is strongly typed as User\nfmt.Printf(\"User: %s (%s)\\n\", response.Data.Name, response.Data.Email)\n```\n\n### Request with Retry Logic\n\n```go\n// Create client with retry logic\nretryClient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    WithRetryStrategy(httpx.ExponentialBackoffStrategy).\n    WithRetryBaseDelay(500 * time.Millisecond).\n    Build()\n\n// Use with generic client\nclient := httpx.NewGenericClient[User](\n    httpx.WithHTTPClient[User](retryClient),\n    httpx.)\n\nresponse, err := client.Get(\"/users/123\")\n```\n\n## Features\n\n### Request Builder\n\nThe `RequestBuilder` provides a fluent, chainable API for constructing HTTP requests with comprehensive validation.\n\n#### Key Features\n\n- ✅ HTTP methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE, CONNECT\n- ✅ Convenience methods for all standard HTTP methods (WithMethodGET, WithMethodPOST, WithMethodPUT, WithMethodDELETE, WithMethodPATCH, WithMethodHEAD, WithMethodOPTIONS, WithMethodTRACE, WithMethodCONNECT)\n- ✅ Query parameters with automatic URL encoding\n- ✅ Custom headers with validation\n- ✅ Authentication (Basic Auth, Bearer Token)\n- ✅ Multiple body formats (JSON, string, bytes, io.Reader)\n- ✅ Context support for timeouts and cancellation\n- ✅ Input validation with error accumulation\n- ✅ Comprehensive error messages\n\n#### Usage Example\n\n```go\nreq, err := httpx.NewRequestBuilder(\"https://api.example.com\").\n    WithMethodPOST().\n    WithPath(\"/users\").\n    WithQueryParam(\"notify\", \"true\").\n    WithHeader(\"Content-Type\", \"application/json\").\n    WithHeader(\"X-Request-ID\", \"unique-id-123\").\n    WithBearerAuth(\"your-token-here\").\n    WithJSONBody(map[string]string{\n        \"name\":  \"John Doe\",\n        \"email\": \"john@example.com\",\n    }).\n    Build()\n\nif err != nil {\n    // Handle validation errors\n    log.Fatal(err)\n}\n```\n\n#### Validation Features\n\nThe RequestBuilder validates inputs and accumulates errors:\n\n```go\nbuilder := httpx.NewRequestBuilder(\"https://api.example.com\")\nbuilder.HTTPMethod(\"\")           // Error: empty method\nbuilder.WithHeader(\"\", \"value\")      // Error: empty header key\nbuilder.WithQueryParam(\"key=\", \"val\") // Error: invalid character in key\n\n// Check for errors before building\nif builder.HasErrors() {\n    for _, err := range builder.GetErrors() {\n        log.Printf(\"Validation error: %v\", err)\n    }\n}\n\n// Or let Build() report all errors\nreq, err := builder.Build()\nif err != nil {\n    // err contains all accumulated validation errors\n    log.Fatal(err)\n}\n```\n\n#### Reset and Reuse\n\n```go\nbuilder := httpx.NewRequestBuilder(\"https://api.example.com\")\n\n// Use builder\nreq1, _ := builder.WithWithMethodGET().WithPath(\"/users\").Build()\n\n// Reset and reuse\nbuilder.Reset()\nreq2, _ := builder.WithWithMethodPOST().WithPath(\"/posts\").Build()\n```\n\n### Generic HTTP Client\n\nThe `GenericClient` provides type-safe HTTP requests with automatic JSON marshaling and unmarshaling using Go generics.\n\n#### Key Features\n\n- 🎯 Type-safe responses with automatic JSON unmarshaling\n- 🔄 Convenience methods: Get, Post, Put, Delete, Patch\n- 🔌 Execute method for use with RequestBuilder\n- 📦 ExecuteRaw for non-JSON responses\n- 🌐 Base URL resolution for relative paths\n- 📋 Default headers applied to all requests\n- ❌ Structured error responses\n- 🔁 Full integration with retry logic\n\n#### Basic Usage\n\n```go\ntype Post struct {\n    ID     int    `json:\"id\"`\n    Title  string `json:\"title\"`\n    Body   string `json:\"body\"`\n    UserID int    `json:\"userId\"`\n}\n\nclient := httpx.NewGenericClient[Post](\n    httpx.WithTimeout[Post](10 * time.Second),\n    httpx.WithMaxRetries[Post](3),\n    httpx.WithRetryStrategy[Post](httpx.ExponentialBackoffStrategy),\n)\n\n// GET request\nresponse, err := client.Get(\"https://api.example.com/posts/1\")\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"Title: %s\\n\", response.Data.Title)\n\n// POST request\nnewPost := Post{Title: \"New Post\", Body: \"Content\", UserID: 1}\npostData, _ := json.Marshal(newPost)\nresponse, err = client.Post(\"https://api.example.com/posts\", bytes.NewReader(postData))\n```\n\n#### With RequestBuilder\n\nCombine GenericClient with RequestBuilder for maximum flexibility:\n\n```go\ntype User struct {\n    ID    int    `json:\"id\"`\n    Name  string `json:\"name\"`\n    Email string `json:\"email\"`\n}\n\nclient := httpx.NewGenericClient[User](\n    httpx.WithTimeout[User](15 * time.Second),\n    httpx.WithMaxRetries[User](3),\n)\n\n// Build complex request\nreq, err := httpx.NewRequestBuilder(\"https://api.example.com\").\n    WithMethodPOST().\n    WithPath(\"/users\").\n    WithContentType(\"application/json\").\n    WithHeader(\"X-Request-ID\", \"unique-123\").\n    WithJSONBody(User{Name: \"Jane\", Email: \"jane@example.com\"}).\n    Build()\n\nif err != nil {\n    log.Fatal(err)\n}\n\n// Execute with type safety\nresponse, err := client.Execute(req)\nif err != nil {\n    log.Fatal(err)\n}\n\nfmt.Printf(\"Created user ID: %d\\n\", response.Data.ID)\n```\n\n#### Error Handling\n\nThe generic client returns structured errors:\n\n```go\nresponse, err := client.Get(\"/users/999999\")\nif err != nil {\n    // Check if it's an API error\n    if apiErr, ok := err.(*httpx.ErrorResponse); ok {\n        fmt.Printf(\"API Error %d: %s\\n\", apiErr.StatusCode, apiErr.Message)\n        // StatusCode: 404\n        // Message: \"User not found\"\n    } else {\n        // Network error, parsing error, etc.\n        log.Printf(\"Request failed: %v\\n\", err)\n    }\n    return\n}\n```\n\n#### Multiple Typed Clients\n\nUse different clients for different response types:\n\n```go\ntype User struct { /* ... */ }\ntype Post struct { /* ... */ }\n\nuserClient := httpx.NewGenericClient[User](\n    httpx.WithTimeout[User](10 * time.Second),\n)\n\npostClient := httpx.NewGenericClient[Post](\n    httpx.WithTimeout[Post](10 * time.Second),\n)\n\n// Fetch user\nuserResp, _ := userClient.Get(\"/users/1\")\n\n// Fetch user's posts\npostsResp, _ := postClient.Get(fmt.Sprintf(\"/users/%d/posts\", userResp.Data.ID))\n```\n\n### Retry Logic\n\nThe package provides transparent retry logic with configurable strategies.\n\n#### Retry Strategies\n\n##### Exponential Backoff (Recommended)\n\nDoubles the wait time between retries:\n\n```go\nclient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    WithRetryStrategy(httpx.ExponentialBackoffStrategy).\n    WithRetryBaseDelay(500 * time.Millisecond).\n    WithRetryMaxDelay(10 * time.Second).\n    Build()\n```\n\nWait times: 500ms → 1s → 2s → 4s (capped at maxDelay)\n\n##### Fixed Delay\n\nWaits a constant duration between retries:\n\n```go\nclient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    WithRetryStrategy(httpx.FixedDelayStrategy).\n    WithRetryBaseDelay(1 * time.Second).\n    Build()\n```\n\nWait times: 1s → 1s → 1s\n\n##### Jitter Backoff\n\nAdds randomization to exponential backoff to prevent thundering herd:\n\n```go\nclient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    WithRetryStrategy(httpx.JitterBackoffStrategy).\n    WithRetryBaseDelay(500 * time.Millisecond).\n    WithRetryMaxDelay(10 * time.Second).\n    Build()\n```\n\nWait times: Random between 0-500ms → 0-1s → 0-2s\n\n#### What Gets Retried?\n\nThe retry logic automatically retries:\n\n- Network errors (connection failures, timeouts)\n- HTTP 5xx server errors (500-599)\n- HTTP 429 (Too Many Requests)\n\nDoes NOT retry:\n\n- HTTP 4xx client errors (except 429)\n- HTTP 2xx/3xx successful responses\n- Requests without GetBody (non-replayable requests)\n\n#### Retry with Generic Client\n\n```go\n// Create retry client\nretryClient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    WithRetryStrategy(httpx.ExponentialBackoffStrategy).\n    Build()\n\n// Use with generic client\nclient := httpx.NewGenericClient[User](\n    httpx.WithHTTPClient[User](retryClient),\n    httpx.)\n\n// Requests automatically retry on failure\nresponse, err := client.Get(\"/users/1\")\n```\n\n### Client Builder\n\nThe `ClientBuilder` provides fine-grained control over HTTP client configuration.\n\n#### Configuration Options\n\n```go\nclient := httpx.NewClientBuilder().\n    // Timeouts\n    WithTimeout(30 * time.Second).\n    WithIdleConnTimeout(90 * time.Second).\n    WithTLSHandshakeTimeout(10 * time.Second).\n    WithExpectContinueTimeout(1 * time.Second).\n\n    // Connection pooling\n    WithMaxIdleConns(100).\n    WithMaxIdleConnsPerHost(10).\n    WithDisableKeepAlive(false).\n\n    // Retry configuration\n    WithMaxRetries(3).\n    WithRetryStrategy(httpx.ExponentialBackoffStrategy).\n    WithRetryBaseDelay(500 * time.Millisecond).\n    WithRetryMaxDelay(10 * time.Second).\n\n    Build()\n```\n\n#### Default Values\n\n| Setting | Default | Valid Range |\n|---------|---------|-------------|\n| Timeout | 5s | 1s - 30s |\n| MaxRetries | 3 | 1 - 10 |\n| RetryBaseDelay | 500ms | 300ms - 5s |\n| RetryMaxDelay | 10s | 300ms - 120s |\n| MaxIdleConns | 100 | 1 - 200 |\n| IdleConnTimeout | 90s | 1s - 120s |\n| TLSHandshakeTimeout | 10s | 1s - 15s |\n\nThe builder validates all settings and uses defaults for out-of-range values.\n\n### Proxy Configuration\n\nThe httpx package provides comprehensive HTTP/HTTPS proxy support across all client types. Configure proxies to route your requests through corporate firewalls, load balancers, or testing proxies.\n\n#### Key Features\n\n- ✅ HTTP and HTTPS proxy support\n- 🔐 Proxy authentication (username/password)\n- 🔄 Works with retry logic\n- 🎯 Compatible with all client types\n- 🌐 Full URL or host:port formats\n- 📝 Graceful fallback on invalid URLs\n\n#### Basic Usage\n\n##### With ClientBuilder\n\n```go\n// HTTP proxy\nclient := httpx.NewClientBuilder().\n    WithProxy(\"http://proxy.example.com:8080\").\n    WithTimeout(10 * time.Second).\n    Build()\n\n// HTTPS proxy\nclient := httpx.NewClientBuilder().\n    WithProxy(\"https://secure-proxy.example.com:3128\").\n    Build()\n```\n\n##### With GenericClient\n\n```go\ntype User struct {\n    ID    int    `json:\"id\"`\n    Name  string `json:\"name\"`\n    Email string `json:\"email\"`\n}\n\nclient := httpx.NewGenericClient[User](\n    httpx.WithProxy[User](\"http://proxy.example.com:8080\"),\n    httpx.WithTimeout[User](10*time.Second),\n    httpx.WithMaxRetries[User](3),\n)\n\nresponse, err := client.Get(\"https://api.example.com/users/1\")\n```\n\n##### With Retry Client\n\n```go\nclient := httpx.NewHTTPRetryClient(\n    httpx.WithProxyRetry(\"http://proxy.example.com:8080\"),\n    httpx.WithMaxRetriesRetry(5),\n    httpx.WithRetryStrategyRetry(\n        httpx.ExponentialBackoff(500*time.Millisecond, 30*time.Second),\n    ),\n)\n```\n\n#### Proxy Authentication\n\nInclude credentials directly in the proxy URL:\n\n```go\nclient := httpx.NewClientBuilder().\n    WithProxy(\"http://username:password@proxy.example.com:8080\").\n    Build()\n```\n\n**Security Note:** For production, consider using environment variables or secret management:\n\n```go\nproxyURL := fmt.Sprintf(\"http://%s:%s@%s:%s\",\n    os.Getenv(\"PROXY_USER\"),\n    os.Getenv(\"PROXY_PASS\"),\n    os.Getenv(\"PROXY_HOST\"),\n    os.Getenv(\"PROXY_PORT\"),\n)\n\nclient := httpx.NewClientBuilder().\n    WithProxy(proxyURL).\n    Build()\n```\n\n#### Common Proxy Ports\n\n- **HTTP Proxy**: 8080, 3128, 8888\n- **HTTPS Proxy**: 3128, 8443\n- **Squid**: 3128 (most common)\n- **Corporate Proxies**: 8080, 80\n\n#### Disable Proxy\n\nOverride environment proxy settings by passing an empty string:\n\n```go\n// Disable proxy (ignore HTTP_PROXY environment variable)\nclient := httpx.NewClientBuilder().\n    WithProxy(\"\").\n    Build()\n```\n\n#### Complete Example\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"time\"\n\n    \"github.com/slashdevops/httpx\"\n)\n\ntype APIResponse struct {\n    Message string `json:\"message\"`\n    Status  string `json:\"status\"`\n}\n\nfunc main() {\n    // Configure client with proxy and full options\n    client := httpx.NewGenericClient[APIResponse](\n        httpx.WithProxy[APIResponse](\"http://proxy.example.com:8080\"),\n        httpx.WithTimeout[APIResponse](15*time.Second),\n        httpx.WithMaxRetries[APIResponse](5),\n        httpx.WithRetryStrategy[APIResponse](httpx.JitterBackoffStrategy),\n        httpx.WithRetryBaseDelay[APIResponse](500*time.Millisecond),\n        httpx.WithRetryMaxDelay[APIResponse](30*time.Second),\n    )\n\n    // Build request with authentication\n    req, err := httpx.NewRequestBuilder(\"https://api.example.com\").\n        WithMethodGET().\n        WithPath(\"/data\").\n        WithBearerAuth(\"your-token-here\").\n        WithHeader(\"Accept\", \"application/json\").\n        Build()\n\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    // Execute through proxy\n    response, err := client.Do(req)\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    fmt.Printf(\"Response: %s\\n\", response.Data.Message)\n}\n```\n\n#### Error Handling\n\nThe library gracefully handles proxy configuration errors:\n\n```go\nclient := httpx.NewClientBuilder().\n    WithProxy(\"://invalid-url\").  // Invalid URL\n    WithLogger(logger).            // Optional: log warnings\n    Build()\n\n// Client builds successfully, but proxy is not configured\n// Warning logged if logger is provided\n```\n\n### Logging\n\nThe httpx package supports optional logging using Go's standard `log/slog` package. **Logging is disabled by default** to maintain clean, silent HTTP operations. Enable it when you need observability into retries, errors, and other HTTP client operations.\n\n#### Quick Start\n\n##### Basic Usage\n\n```go\nimport (\n    \"log/slog\"\n    \"os\"\n\n    \"github.com/slashdevops/httpx\"\n)\n\n// Create a logger\nlogger := slog.New(slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{\n    Level: slog.LevelWarn,\n}))\n\n// Use with ClientBuilder\nclient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    WithLogger(logger).  // Enable logging\n    Build()\n```\n\n##### With Generic Client\n\n```go\ntype User struct {\n    ID   int    `json:\"id\"`\n    Name string `json:\"name\"`\n}\n\nlogger := slog.New(slog.NewJSONHandler(os.Stderr, nil))\n\nclient := httpx.NewGenericClient[User](\n    httpx.WithMaxRetries[User](3),\n    httpx.WithLogger[User](logger),\n)\n```\n\n##### With NewHTTPRetryClient\n\n```go\nlogger := slog.New(slog.NewTextHandler(os.Stdout, nil))\n\nclient := httpx.NewHTTPRetryClient(\n    httpx.WithMaxRetriesRetry(3),\n    httpx.WithRetryStrategyRetry(httpx.ExponentialBackoff(500*time.Millisecond, 10*time.Second)),\n    httpx.WithLoggerRetry(logger),\n)\n```\n\n#### What Gets Logged\n\n##### Retry Attempts (Warn Level)\n\nWhen a request fails and is being retried:\n\n```\ntime=2026-01-17T21:00:00.000+00:00 level=WARN msg=\"HTTP request returned server error, retrying\" attempt=1 max_retries=3 delay=500ms status_code=500 url=https://api.example.com/users method=GET\n```\n\nAttributes logged:\n\n- `attempt`: Current retry attempt number (1-indexed)\n- `max_retries`: Maximum number of retries configured\n- `delay`: How long the client will wait before retrying\n- `status_code`: HTTP status code (for server errors) OR\n- `error`: Error message (for network/connection errors)\n- `url`: Full request URL\n- `method`: HTTP method (GET, POST, etc.)\n\n##### All Retries Failed (Error Level)\n\nWhen all retry attempts are exhausted:\n\n```\ntime=2026-01-17T21:00:00.500+00:00 level=ERROR msg=\"All retry attempts failed\" attempts=4 status_code=503 url=https://api.example.com/users method=GET\n```\n\nAttributes logged:\n\n- `attempts`: Total number of attempts made (including initial request)\n- `status_code` OR `error`: Final failure reason\n- `url`: Full request URL\n- `method`: HTTP method\n\n#### Logger Configuration\n\n##### Log Levels\n\nChoose the appropriate log level based on your needs:\n\n```go\n// Only log final failures (recommended for production)\nlogger := slog.New(slog.NewJSONHandler(os.Stderr, \u0026slog.HandlerOptions{\n    Level: slog.LevelError,\n}))\n\n// Log all retry attempts (useful for debugging)\nlogger := slog.New(slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{\n    Level: slog.LevelWarn,\n}))\n\n// Log everything including debug info from other packages\nlogger := slog.New(slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{\n    Level: slog.LevelDebug,\n}))\n```\n\n##### Output Formats\n\n###### Text Format (Development)\n\nBest for human readability during development:\n\n```go\nlogger := slog.New(slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{\n    Level: slog.LevelWarn,\n}))\n```\n\nOutput:\n\n```\ntime=2026-01-17T21:00:00.000+00:00 level=WARN msg=\"HTTP request returned server error, retrying\" attempt=1 max_retries=3 delay=500ms status_code=500\n```\n\n###### JSON Format (Production)\n\nBest for structured logging and log aggregation:\n\n```go\nlogger := slog.New(slog.NewJSONHandler(os.Stderr, \u0026slog.HandlerOptions{\n    Level: slog.LevelError,\n}))\n```\n\nOutput:\n\n```json\n{\"time\":\"2026-01-17T21:00:00.000Z\",\"level\":\"ERROR\",\"msg\":\"All retry attempts failed\",\"attempts\":4,\"status_code\":503,\"url\":\"https://api.example.com/users\",\"method\":\"GET\"}\n```\n\n##### Writing to Files\n\n```go\nlogFile, err := os.OpenFile(\"http.log\", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)\nif err != nil {\n    log.Fatal(err)\n}\ndefer logFile.Close()\n\nlogger := slog.New(slog.NewJSONHandler(logFile, \u0026slog.HandlerOptions{\n    Level: slog.LevelWarn,\n}))\n```\n\n#### Logging Best Practices\n\n1. **Default to No Logging**: Keep logging disabled in production unless actively troubleshooting:\n\n   ```go\n   // Production - no logging (default)\n   client := httpx.NewClientBuilder().\n       WithMaxRetries(3).\n       Build()  // No WithLogger() call = no logging\n   ```\n\n2. **Use Structured Logging in Production**: JSON format is machine-readable and works well with log aggregators:\n\n   ```go\n   logger := slog.New(slog.NewJSONHandler(os.Stderr, \u0026slog.HandlerOptions{\n       Level: slog.LevelError,  // Only final failures\n   }))\n   ```\n\n3. **Enable for Specific Troubleshooting**: Turn on logging temporarily when investigating issues:\n\n   ```go\n   // Temporarily enable for debugging\n   var logger *slog.Logger\n   if os.Getenv(\"DEBUG_HTTP\") != \"\" {\n       logger = slog.New(slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{\n           Level: slog.LevelWarn,\n       }))\n   }\n\n   client := httpx.NewClientBuilder().\n       WithMaxRetries(3).\n       WithLogger(logger).  // Will be nil if not debugging\n       Build()\n   ```\n\n4. **Add Context with Attributes**: Enhance logs with additional context:\n\n   ```go\n   // Create logger with service context\n   logger := slog.New(slog.NewJSONHandler(os.Stderr, nil)).\n       With(\"service\", \"api-client\").\n       With(\"version\", \"1.0.0\")\n\n   client := httpx.NewClientBuilder().\n       WithLogger(logger).\n       Build()\n   ```\n\n5. **Different Loggers for Different Clients**: Use separate loggers for different clients to distinguish traffic:\n\n   ```go\n   // User service client\n   userLogger := slog.New(slog.NewJSONHandler(os.Stderr, nil)).\n       With(\"client\", \"user-service\")\n   userClient := httpx.NewClientBuilder().\n       WithLogger(userLogger).\n       Build()\n\n   // Payment service client\n   paymentLogger := slog.New(slog.NewJSONHandler(os.Stderr, nil)).\n       With(\"client\", \"payment-service\")\n   paymentClient := httpx.NewClientBuilder().\n       WithLogger(paymentLogger).\n       Build()\n   ```\n\n#### Performance Considerations\n\n- **Minimal Overhead**: When logging is disabled (logger is `nil`), the overhead is just a simple nil check\n- **No Allocations**: Log statements use slog's efficient attribute system\n- **Deferred Work**: The logger only formats messages if the log level is enabled\n\n#### Disabling Logging\n\nSimply pass `nil` or omit the logger:\n\n```go\n// Explicitly pass nil\nclient := httpx.NewClientBuilder().\n    WithLogger(nil).  // No logging\n    Build()\n\n// Or just don't call WithLogger\nclient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    Build()  // No logging (default)\n```\n\n#### Migration Guide\n\nIf you have existing code without logging, no changes are needed. The feature is fully backward compatible:\n\n```go\n// Old code - still works, no logging\nclient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    Build()\n\n// New code - add logging when needed\nlogger := slog.New(slog.NewTextHandler(os.Stdout, nil))\nclient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    WithLogger(logger).  // Just add this line\n    Build()\n```\n\n#### Logging Examples\n\n##### Example 1: Development Debugging\n\n```go\npackage main\n\nimport (\n    \"log/slog\"\n    \"os\"\n    \"time\"\n\n    \"github.com/slashdevops/httpx\"\n)\n\nfunc main() {\n    // Text output with warn level for debugging\n    logger := slog.New(slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{\n        Level: slog.LevelWarn,\n    }))\n\n    client := httpx.NewClientBuilder().\n        WithMaxRetries(3).\n        WithRetryBaseDelay(500 * time.Millisecond).\n        WithLogger(logger).\n        Build()\n\n    // You'll see retry attempts in the console\n    resp, err := client.Get(\"https://api.example.com/flaky-endpoint\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer resp.Body.Close()\n}\n```\n\n##### Example 2: Production Monitoring\n\n```go\npackage main\n\nimport (\n    \"log/slog\"\n    \"os\"\n\n    \"github.com/slashdevops/httpx\"\n)\n\nfunc main() {\n    // JSON output, only errors, to stderr\n    logger := slog.New(slog.NewJSONHandler(os.Stderr, \u0026slog.HandlerOptions{\n        Level: slog.LevelError,\n    })).With(\n        \"service\", \"payment-processor\",\n        \"environment\", \"production\",\n    )\n\n    client := httpx.NewClientBuilder().\n        WithMaxRetries(3).\n        WithLogger(logger).\n        Build()\n\n    // Only final failures will be logged\n    resp, err := client.Get(\"https://payment-api.example.com/status\")\n    // ...\n}\n```\n\n##### Example 3: Conditional Logging\n\n```go\npackage main\n\nimport (\n    \"log/slog\"\n    \"os\"\n\n    \"github.com/slashdevops/httpx\"\n)\n\nfunc createClient() *http.Client {\n    var logger *slog.Logger\n\n    // Only enable logging if DEBUG environment variable is set\n    if os.Getenv(\"DEBUG\") != \"\" {\n        logger = slog.New(slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{\n            Level: slog.LevelDebug,\n        }))\n    }\n\n    return httpx.NewClientBuilder().\n        WithMaxRetries(3).\n        WithLogger(logger).  // Will be nil in production\n        Build()\n}\n```\n\n#### Troubleshooting\n\n##### Not Seeing Any Logs?\n\n1. **Check logger level**: Make sure the level is set to at least `LevelWarn`:\n\n   ```go\n   logger := slog.New(slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{\n       Level: slog.LevelWarn,  // Not Info or Debug\n   }))\n   ```\n\n2. **Verify logger is passed**: Make sure you called `WithLogger()`:\n\n   ```go\n   client := httpx.NewClientBuilder().\n       WithLogger(logger).  // Don't forget this!\n       Build()\n   ```\n\n3. **Check if retries are happening**: Logs only appear when requests fail and retry. Successful first attempts don't log.\n\n##### Too Many Logs?\n\n1. **Increase log level** to `LevelError` to only see final failures\n2. **Disable logging** in production environments where retry behavior is well understood\n3. **Use sampling** if your log aggregation system supports it\n\n#### Logging Summary\n\nThe logging feature in httpx provides:\n\n- ✅ **Optional** - Disabled by default, zero overhead when not in use\n- ✅ **Standard** - Uses Go's `log/slog` package\n- ✅ **Flexible** - Configurable output format, level, and destination\n- ✅ **Informative** - Rich attributes for debugging and monitoring\n- ✅ **Backward Compatible** - Existing code works without changes\n\nEnable it when you need visibility, keep it off for clean, silent operations.\n\n## Examples\n\n### Complete Example: CRUD Operations\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"time\"\n\n    \"github.com/slashdevops/httpx\"\n)\n\ntype Todo struct {\n    ID        int    `json:\"id\"`\n    Title     string `json:\"title\"`\n    Completed bool   `json:\"completed\"`\n    UserID    int    `json:\"userId\"`\n}\n\nfunc main() {\n    // Create retry client\n    retryClient := httpx.NewClientBuilder().\n        WithMaxRetries(3).\n        WithRetryStrategy(httpx.ExponentialBackoffStrategy).\n        WithTimeout(10 * time.Second).\n        Build()\n\n    // Create typed client\n    client := httpx.NewGenericClient[Todo](\n        httpx.WithHTTPClient[Todo](retryClient),\n        httpx.        httpx.    )\n\n    // GET - Read\n    fmt.Println(\"Fetching todo...\")\n    todo, err := client.Get(\"/todos/1\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Todo: %s (completed: %v)\\n\", todo.Data.Title, todo.Data.Completed)\n\n    // POST - Create\n    fmt.Println(\"\\nCreating new todo...\")\n    newTodo := Todo{\n        Title:     \"Learn httputils\",\n        Completed: false,\n        UserID:    1,\n    }\n\n    req, _ := httpx.NewRequestBuilder(\"https://jsonplaceholder.typicode.com\").\n        WithMethodPOST().\n        WithPath(\"/todos\").\n        WithContentType(\"application/json\").\n        WithJSONBody(newTodo).\n        Build()\n\n    created, err := client.Execute(req)\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Created todo ID: %d\\n\", created.Data.ID)\n\n    // PUT - Update\n    fmt.Println(\"\\nUpdating todo...\")\n    updateTodo := created.Data\n    updateTodo.Completed = true\n\n    req, _ = httpx.NewRequestBuilder(\"https://jsonplaceholder.typicode.com\").\n        WithMethodPUT().\n        WithPath(fmt.Sprintf(\"/todos/%d\", updateTodo.ID)).\n        WithContentType(\"application/json\").\n        WithJSONBody(updateTodo).\n        Build()\n\n    updated, err := client.Execute(req)\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Updated: completed = %v\\n\", updated.Data.Completed)\n\n    // DELETE\n    fmt.Println(\"\\nDeleting todo...\")\n    deleteResp, err := client.Delete(fmt.Sprintf(\"/todos/%d\", updateTodo.ID))\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Deleted (status: %d)\\n\", deleteResp.StatusCode)\n}\n```\n\n### Authentication Example\n\n```go\n// Basic Authentication\nreq, err := httpx.NewRequestBuilder(\"https://api.example.com\").\n    WithMethodGET().\n    WithPath(\"/protected/resource\").\n    WithBasicAuth(\"username\", \"password\").\n    Build()\n\n// Bearer Token Authentication\nreq, err := httpx.NewRequestBuilder(\"https://api.example.com\").\n    WithMethodGET().\n    WithPath(\"/protected/resource\").\n    WithBearerAuth(\"your-jwt-token\").\n    Build()\n\n// With Generic Client\nclient := httpx.NewGenericClient[Resource](\n    httpx.    httpx.)\n```\n\n### Context and Timeout\n\n```go\n// Request with timeout\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\ndefer cancel()\n\nreq, err := httpx.NewRequestBuilder(\"https://api.example.com\").\n    WithMethodGET().\n    WithPath(\"/slow-endpoint\").\n    Context(ctx).\n    Build()\n\n// Request with cancellation\nctx, cancel := context.WithCancel(context.Background())\n\ngo func() {\n    time.Sleep(2 * time.Second)\n    cancel() // Cancel after 2 seconds\n}()\n\nreq, err := httpx.NewRequestBuilder(\"https://api.example.com\").\n    WithMethodGET().\n    WithPath(\"/endpoint\").\n    Context(ctx).\n    Build()\n```\n\n### Custom Headers and Query Parameters\n\n```go\nreq, err := httpx.NewRequestBuilder(\"https://api.example.com\").\n    WithMethodGET().\n    WithPath(\"/search\").\n    WithQueryParam(\"q\", \"golang\").\n    WithQueryParam(\"sort\", \"relevance\").\n    WithQueryParam(\"limit\", \"10\").\n    WithHeader(\"Accept\", \"application/json\").\n    WithHeader(\"Accept-Language\", \"en-US\").\n    WithHeader(\"X-Request-ID\", generateRequestID()).\n    WithHeader(\"X-Correlation-ID\", getCorrelationID()).\n    WithUserAgent(\"MyApp/1.0 (Go)\").\n    Build()\n```\n\n## API Reference\n\n### RequestBuilder\n\n#### Constructor\n\n- `NewRequestBuilder(baseURL string) *RequestBuilder`\n\n#### HTTP Methods\n\n- `WithMethodGET() *RequestBuilder`\n- `WithMethodPOST() *RequestBuilder`\n- `WithMethodPUT() *RequestBuilder`\n- `WithMethodDELETE() *RequestBuilder`\n- `WithMethodPATCH() *RequestBuilder`\n- `WithMethodHEAD() *RequestBuilder`\n- `WithMethodOPTIONS() *RequestBuilder`\n- `WithMethodTRACE() *RequestBuilder`\n- `WithMethodCONNECT() *RequestBuilder`\n- `WithMethod(method string) *RequestBuilder` - Custom HTTP method with validation\n\n#### URL and Parameters\n\n- `WithPath(path string) *RequestBuilder` - Set URL path\n- `WithQueryParam(key, value string) *RequestBuilder` - Add single query parameter\n- `QueryParams(params map[string]string) *RequestBuilder` - Add multiple query parameters\n\n#### Headers\n\n- `WithHeader(key, value string) *RequestBuilder` - Set single header\n- `Headers(headers map[string]string) *RequestBuilder` - Set multiple headers\n- `WithContentType(contentType string) *RequestBuilder` - Set Content-Type header\n- `WithAccept(accept string) *RequestBuilder` - Set Accept header\n- `WithUserAgent(userAgent string) *RequestBuilder` - Set User-Agent header\n\n#### Authentication\n\n- `WithBasicAuth(username, password string) *RequestBuilder` - Set Basic authentication\n- `WithBearerAuth(token string) *RequestBuilder` - Set Bearer token authentication\n\n#### Body\n\n- `WithJSONBody(body any) *RequestBuilder` - Set JSON body (auto-marshals)\n- `RawBody(body io.Reader) *RequestBuilder` - Set raw body\n- `WithStringBody(body string) *RequestBuilder` - Set string body\n- `BytesBody(body []byte) *RequestBuilder` - Set bytes body\n\n#### Other\n\n- `Context(ctx context.Context) *RequestBuilder` - Set request context\n- `Build() (*http.Request, error)` - Build and validate request\n\n#### Error Handling\n\n- `HasErrors() bool` - Check if there are validation errors\n- `GetErrors() []error` - Get all validation errors\n- `Reset() *RequestBuilder` - Reset builder state\n\n### GenericClient[T any]\n\n#### Constructor\n\n- `NewGenericClient[T any](options ...GenericClientOption[T]) *GenericClient[T]`\n\n#### Options\n\n- `WithHTTPClient[T any](httpClient HTTPClient) GenericClientOption[T]` - Use a pre-configured HTTP client (takes precedence)\n- `WithTimeout[T any](timeout time.Duration) GenericClientOption[T]` - Set request timeout\n- `WithMaxRetries[T any](maxRetries int) GenericClientOption[T]` - Set maximum retry attempts\n- `WithRetryStrategy[T any](strategy Strategy) GenericClientOption[T]` - Set retry strategy (fixed, jitter, exponential)\n- `WithRetryStrategyAsString[T any](strategy string) GenericClientOption[T]` - Set retry strategy from string\n- `WithRetryBaseDelay[T any](baseDelay time.Duration) GenericClientOption[T]` - Set base delay for retry strategies\n- `WithRetryMaxDelay[T any](maxDelay time.Duration) GenericClientOption[T]` - Set maximum delay for retry strategies\n- `WithMaxIdleConns[T any](maxIdleConns int) GenericClientOption[T]` - Set maximum idle connections\n- `WithIdleConnTimeout[T any](idleConnTimeout time.Duration) GenericClientOption[T]` - Set idle connection timeout\n- `WithTLSHandshakeTimeout[T any](tlsHandshakeTimeout time.Duration) GenericClientOption[T]` - Set TLS handshake timeout\n- `WithExpectContinueTimeout[T any](expectContinueTimeout time.Duration) GenericClientOption[T]` - Set expect continue timeout\n- `WithMaxIdleConnsPerHost[T any](maxIdleConnsPerHost int) GenericClientOption[T]` - Set maximum idle connections per host\n- `WithDisableKeepAlive[T any](disableKeepAlive bool) GenericClientOption[T]` - Disable HTTP keep-alive\n\n#### Methods\n\n- `Execute(req *http.Request) (*Response[T], error)` - Execute request with type safety\n- `ExecuteRaw(req *http.Request) (*http.Response, error)` - Execute and return raw response\n- `Do(req *http.Request) (*Response[T], error)` - Alias for Execute\n- `Get(url string) (*Response[T], error)` - Execute GET request\n- `Post(url string, body io.Reader) (*Response[T], error)` - Execute POST request\n- `Put(url string, body io.Reader) (*Response[T], error)` - Execute PUT request\n- `Delete(url string) (*Response[T], error)` - Execute DELETE request\n- `Patch(url string, body io.Reader) (*Response[T], error)` - Execute PATCH request\n- `GetBaseURL() string` - Get configured base URL\n- `GetDefaultHeaders() map[string]string` - Get configured headers\n\n### ClientBuilder\n\n#### Constructor\n\n- `NewClientBuilder() *ClientBuilder`\n\n#### Configuration Methods\n\n- `WithTimeout(timeout time.Duration) *ClientBuilder`\n- `WithMaxRetries(maxRetries int) *ClientBuilder`\n- `WithRetryStrategy(strategy Strategy) *ClientBuilder`\n- `WithRetryBaseDelay(baseDelay time.Duration) *ClientBuilder`\n- `WithRetryMaxDelay(maxDelay time.Duration) *ClientBuilder`\n- `WithMaxIdleConns(maxIdleConns int) *ClientBuilder`\n- `WithMaxIdleConnsPerHost(maxIdleConnsPerHost int) *ClientBuilder`\n- `WithIdleConnTimeout(idleConnTimeout time.Duration) *ClientBuilder`\n- `WithTLSHandshakeTimeout(tlsHandshakeTimeout time.Duration) *ClientBuilder`\n- `WithExpectContinueTimeout(expectContinueTimeout time.Duration) *ClientBuilder`\n- `WithDisableKeepAlive(disableKeepAlive bool) *ClientBuilder`\n- `Build() *http.Client` - Build configured client\n\n### Retry Strategies\n\n- `ExponentialBackoff(base, maxDelay time.Duration) RetryStrategy`\n- `FixedDelay(delay time.Duration) RetryStrategy`\n- `JitterBackoff(base, maxDelay time.Duration) RetryStrategy`\n\n### Types\n\n#### Response[T any]\n\n```go\ntype Response[T any] struct {\n    Data       T           // Parsed response data\n    StatusCode int         // HTTP status code\n    Headers    http.Header // Response headers\n    RawBody    []byte      // Raw response body\n}\n```\n\n#### ErrorResponse\n\n```go\ntype ErrorResponse struct {\n    Message    string `json:\"message,omitempty\"`\n    StatusCode int    `json:\"statusCode,omitempty\"`\n    ErrorMsg   string `json:\"error,omitempty\"`\n    Details    string `json:\"details,omitempty\"`\n}\n```\n\n#### Strategy\n\n```go\nconst (\n    FixedDelayStrategy         Strategy = \"fixed\"\n    JitterBackoffStrategy      Strategy = \"jitter\"\n    ExponentialBackoffStrategy Strategy = \"exponential\"\n)\n```\n\n## Best Practices\n\n### 1. Always Check for Errors\n\n```go\nreq, err := httpx.NewRequestBuilder(baseURL).\n    WithMethodGET().\n    WithPath(\"/endpoint\").\n    Build()\n\nif err != nil {\n    log.Printf(\"Request building failed: %v\", err)\n    return\n}\n```\n\n### 2. Use Type-Safe Clients for JSON APIs\n\n```go\n// Define your model\ntype User struct {\n    ID   int    `json:\"id\"`\n    Name string `json:\"name\"`\n}\n\n// Create typed client\nclient := httpx.NewGenericClient[User](\n    httpx.)\n\n// Enjoy type safety\nresponse, err := client.Get(\"/users/1\")\n// response.Data is User, not interface{}\n```\n\n### 3. Configure Retry Logic for Production\n\n```go\nclient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    WithRetryStrategy(httpx.ExponentialBackoffStrategy).\n    WithRetryBaseDelay(500 * time.Millisecond).\n    WithRetryMaxDelay(10 * time.Second).\n    WithTimeout(30 * time.Second).\n    Build()\n```\n\n### 4. Reuse HTTP Clients\n\n```go\n// Create once, reuse many times\nretryClient := httpx.NewClientBuilder().\n    WithMaxRetries(3).\n    Build()\n\nuserClient := httpx.NewGenericClient[User](\n    httpx.WithHTTPClient[User](retryClient),\n)\n\npostClient := httpx.NewGenericClient[Post](\n    httpx.WithHTTPClient[Post](retryClient),\n)\n```\n\n### 5. Use Context for Timeouts\n\n```go\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\ndefer cancel()\n\nreq, err := httpx.NewRequestBuilder(baseURL).\n    WithMethodGET().\n    WithPath(\"/endpoint\").\n    Context(ctx).\n    Build()\n```\n\n### 6. Validate Before Building\n\n```go\nbuilder := httpx.NewRequestBuilder(baseURL).\n    WithMethodGET().\n    WithPath(\"/endpoint\")\n\n// Add potentially invalid inputs\nbuilder.WithHeader(userProvidedKey, userProvidedValue)\nbuilder.WithQueryParam(userProvidedParam, userProvidedValue)\n\n// Check for errors before building\nif builder.HasErrors() {\n    for _, err := range builder.GetErrors() {\n        log.Printf(\"Validation error: %v\", err)\n    }\n    return\n}\n\nreq, err := builder.Build()\n```\n\n### 7. Handle API Errors Properly\n\n```go\nresponse, err := client.Get(\"/resource\")\nif err != nil {\n    if apiErr, ok := err.(*httpx.ErrorResponse); ok {\n        switch apiErr.StatusCode {\n        case 404:\n            log.Printf(\"Resource not found: %s\", apiErr.Message)\n        case 401:\n            log.Printf(\"Authentication failed: %s\", apiErr.Message)\n        case 429:\n            log.Printf(\"Rate limit exceeded: %s\", apiErr.Message)\n        default:\n            log.Printf(\"API error %d: %s\", apiErr.StatusCode, apiErr.Message)\n        }\n    } else {\n        log.Printf(\"Network error: %v\", err)\n    }\n\n    return\n}\n```\n\n## Thread Safety\n\nAll utilities in this package are safe for concurrent use:\n\n```go\nclient := httpx.NewGenericClient[User](\n    httpx.)\n\n// Safe to use from multiple goroutines\nvar wg sync.WaitGroup\nfor i := 1; i \u003c= 10; i++ {\n    wg.Add(1)\n    go func(id int) {\n        defer wg.Done()\n        user, err := client.Get(fmt.Sprintf(\"/users/%d\", id))\n        if err != nil {\n            log.Printf(\"Error fetching user %d: %v\", id, err)\n            return\n        }\n        log.Printf(\"Fetched user: %s\", user.Data.Name)\n    }(i)\n}\n\nwg.Wait()\n```\n\n## Testing\n\nThe package has comprehensive test coverage (88%+):\n\n```bash\ngo test ./... -v\ngo test ./... -cover\n```\n\n## Contributing\n\nContributions are welcome! Please ensure:\n\n1. Build passes: `go build ./...`\n2. All tests pass: `go test ./...`\n3. Code is formatted: `go fmt ./...`\n4. Linters pass: `golangci-lint run ./...`\n5. Add tests for new features\n6. Update documentation\n\n## License\n\nApache License 2.0. See [LICENSE](LICENSE) for details.\n\n## Credits\n\nDeveloped by the slashdevops team using Agentic Development. Inspired by popular HTTP client libraries and Go best practices.\n","funding_links":["https://github.com/sponsors/christiangda","https://liberapay.com/christiangda","https://patreon.com/christiangda","https://paypal.me/slashdevops"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslashdevops%2Fhttpx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslashdevops%2Fhttpx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslashdevops%2Fhttpx/lists"}