Skip to content

Commit 4d040aa

Browse files
authored
feat: support proxy in transport layer (#3)
1 parent 62eeba1 commit 4d040aa

9 files changed

Lines changed: 816 additions & 0 deletions

README.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ A comprehensive Go package for building and executing HTTP requests with advance
1818
- 🎯 **Type-Safe Generic Client** - Go generics for type-safe HTTP responses
1919
-**Input Validation** - Comprehensive validation with error accumulation
2020
- 🔐 **Authentication Support** - Built-in Basic and Bearer token authentication
21+
- 🌐 **Proxy Support** - HTTP/HTTPS proxy configuration with authentication (supports corporate proxies, authenticated proxies, and custom ports)
2122
- 📝 **Optional Logging** - slog integration for observability (disabled by default)
2223
- 📦 **Zero External Dependencies** - Only Go standard library, no third-party packages
2324

@@ -31,6 +32,7 @@ A comprehensive Go package for building and executing HTTP requests with advance
3132
- [Generic HTTP Client](#generic-http-client)
3233
- [Retry Logic](#retry-logic)
3334
- [Client Builder](#client-builder)
35+
- [Proxy Configuration](#proxy-configuration)
3436
- [Logging](#logging)
3537
- [Examples](#examples)
3638
- [API Reference](#api-reference)
@@ -446,6 +448,174 @@ client := httpx.NewClientBuilder().
446448

447449
The builder validates all settings and uses defaults for out-of-range values.
448450

451+
### Proxy Configuration
452+
453+
The 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.
454+
455+
#### Key Features
456+
457+
- ✅ HTTP and HTTPS proxy support
458+
- 🔐 Proxy authentication (username/password)
459+
- 🔄 Works with retry logic
460+
- 🎯 Compatible with all client types
461+
- 🌐 Full URL or host:port formats
462+
- 📝 Graceful fallback on invalid URLs
463+
464+
#### Basic Usage
465+
466+
##### With ClientBuilder
467+
468+
```go
469+
// HTTP proxy
470+
client := httpx.NewClientBuilder().
471+
WithProxy("http://proxy.example.com:8080").
472+
WithTimeout(10 * time.Second).
473+
Build()
474+
475+
// HTTPS proxy
476+
client := httpx.NewClientBuilder().
477+
WithProxy("https://secure-proxy.example.com:3128").
478+
Build()
479+
```
480+
481+
##### With GenericClient
482+
483+
```go
484+
type User struct {
485+
ID int `json:"id"`
486+
Name string `json:"name"`
487+
Email string `json:"email"`
488+
}
489+
490+
client := httpx.NewGenericClient[User](
491+
httpx.WithProxy[User]("http://proxy.example.com:8080"),
492+
httpx.WithTimeout[User](10*time.Second),
493+
httpx.WithMaxRetries[User](3),
494+
)
495+
496+
response, err := client.Get("https://api.example.com/users/1")
497+
```
498+
499+
##### With Retry Client
500+
501+
```go
502+
client := httpx.NewHTTPRetryClient(
503+
httpx.WithProxyRetry("http://proxy.example.com:8080"),
504+
httpx.WithMaxRetriesRetry(5),
505+
httpx.WithRetryStrategyRetry(
506+
httpx.ExponentialBackoff(500*time.Millisecond, 30*time.Second),
507+
),
508+
)
509+
```
510+
511+
#### Proxy Authentication
512+
513+
Include credentials directly in the proxy URL:
514+
515+
```go
516+
client := httpx.NewClientBuilder().
517+
WithProxy("http://username:password@proxy.example.com:8080").
518+
Build()
519+
```
520+
521+
**Security Note:** For production, consider using environment variables or secret management:
522+
523+
```go
524+
proxyURL := fmt.Sprintf("http://%s:%s@%s:%s",
525+
os.Getenv("PROXY_USER"),
526+
os.Getenv("PROXY_PASS"),
527+
os.Getenv("PROXY_HOST"),
528+
os.Getenv("PROXY_PORT"),
529+
)
530+
531+
client := httpx.NewClientBuilder().
532+
WithProxy(proxyURL).
533+
Build()
534+
```
535+
536+
#### Common Proxy Ports
537+
538+
- **HTTP Proxy**: 8080, 3128, 8888
539+
- **HTTPS Proxy**: 3128, 8443
540+
- **Squid**: 3128 (most common)
541+
- **Corporate Proxies**: 8080, 80
542+
543+
#### Disable Proxy
544+
545+
Override environment proxy settings by passing an empty string:
546+
547+
```go
548+
// Disable proxy (ignore HTTP_PROXY environment variable)
549+
client := httpx.NewClientBuilder().
550+
WithProxy("").
551+
Build()
552+
```
553+
554+
#### Complete Example
555+
556+
```go
557+
package main
558+
559+
import (
560+
"fmt"
561+
"log"
562+
"time"
563+
564+
"github.com/slashdevops/httpx"
565+
)
566+
567+
type APIResponse struct {
568+
Message string `json:"message"`
569+
Status string `json:"status"`
570+
}
571+
572+
func main() {
573+
// Configure client with proxy and full options
574+
client := httpx.NewGenericClient[APIResponse](
575+
httpx.WithProxy[APIResponse]("http://proxy.example.com:8080"),
576+
httpx.WithTimeout[APIResponse](15*time.Second),
577+
httpx.WithMaxRetries[APIResponse](5),
578+
httpx.WithRetryStrategy[APIResponse](httpx.JitterBackoffStrategy),
579+
httpx.WithRetryBaseDelay[APIResponse](500*time.Millisecond),
580+
httpx.WithRetryMaxDelay[APIResponse](30*time.Second),
581+
)
582+
583+
// Build request with authentication
584+
req, err := httpx.NewRequestBuilder("https://api.example.com").
585+
WithMethodGET().
586+
WithPath("/data").
587+
WithBearerAuth("your-token-here").
588+
WithHeader("Accept", "application/json").
589+
Build()
590+
591+
if err != nil {
592+
log.Fatal(err)
593+
}
594+
595+
// Execute through proxy
596+
response, err := client.Do(req)
597+
if err != nil {
598+
log.Fatal(err)
599+
}
600+
601+
fmt.Printf("Response: %s\n", response.Data.Message)
602+
}
603+
```
604+
605+
#### Error Handling
606+
607+
The library gracefully handles proxy configuration errors:
608+
609+
```go
610+
client := httpx.NewClientBuilder().
611+
WithProxy("://invalid-url"). // Invalid URL
612+
WithLogger(logger). // Optional: log warnings
613+
Build()
614+
615+
// Client builds successfully, but proxy is not configured
616+
// Warning logged if logger is provided
617+
```
618+
449619
### Logging
450620

451621
The 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.

docs.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
// - WithExpectContinueTimeout: Set expect continue timeout
148148
// - WithMaxIdleConnsPerHost: Set maximum idle connections per host
149149
// - WithDisableKeepAlive: Disable HTTP keep-alive
150+
// - WithProxy: Configure HTTP/HTTPS proxy server
150151
// - WithHTTPClient: Use a pre-configured HTTP client (takes precedence)
151152
//
152153
// Integration with RequestBuilder:
@@ -257,6 +258,9 @@
257258
// WithRetryBaseDelay(500 * time.Millisecond).
258259
// WithRetryMaxDelay(10 * time.Second).
259260
//
261+
// // Proxy configuration
262+
// WithProxy("http://proxy.example.com:8080").
263+
//
260264
// Build()
261265
//
262266
// Combine with GenericClient:
@@ -360,6 +364,65 @@
360364
// // Handle specific status codes
361365
// }
362366
//
367+
// # Proxy Configuration
368+
//
369+
// The package provides comprehensive proxy support for all HTTP clients.
370+
// Proxy configuration works transparently across all client types and
371+
// supports both HTTP and HTTPS proxies with optional authentication.
372+
//
373+
// Basic proxy configuration with ClientBuilder:
374+
//
375+
// client := httpx.NewClientBuilder().
376+
// WithProxy("http://proxy.example.com:8080").
377+
// Build()
378+
//
379+
// HTTPS proxy:
380+
//
381+
// client := httpx.NewClientBuilder().
382+
// WithProxy("https://secure-proxy.example.com:3128").
383+
// Build()
384+
//
385+
// Proxy with authentication:
386+
//
387+
// client := httpx.NewClientBuilder().
388+
// WithProxy("http://username:password@proxy.example.com:8080").
389+
// Build()
390+
//
391+
// Proxy with GenericClient:
392+
//
393+
// client := httpx.NewGenericClient[User](
394+
// httpx.WithProxy[User]("http://proxy.example.com:8080"),
395+
// httpx.WithTimeout[User](10*time.Second),
396+
// httpx.WithMaxRetries[User](3),
397+
// )
398+
//
399+
// Proxy with retry client:
400+
//
401+
// client := httpx.NewHTTPRetryClient(
402+
// httpx.WithProxyRetry("http://proxy.example.com:8080"),
403+
// httpx.WithMaxRetriesRetry(5),
404+
// )
405+
//
406+
// Disable proxy (override environment variables):
407+
//
408+
// client := httpx.NewClientBuilder().
409+
// WithProxy(""). // Empty string disables proxy
410+
// Build()
411+
//
412+
// Common proxy ports:
413+
// - HTTP proxy: 8080, 3128, 8888
414+
// - HTTPS proxy: 3128, 8443
415+
// - SOCKS proxy: 1080 (not directly supported, use custom transport)
416+
//
417+
// The proxy configuration:
418+
// - Works transparently with all request types
419+
// - Preserves all headers and authentication
420+
// - Compatible with retry logic
421+
// - Supports connection pooling
422+
// - Respects timeout settings
423+
// - Validates proxy URL format
424+
// - Falls back gracefully on invalid URLs
425+
//
363426
// # Thread Safety
364427
//
365428
// All utilities in this package are safe for concurrent use across multiple goroutines:

0 commit comments

Comments
 (0)