httpc

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Dec 10, 2025 License: MIT Imports: 18 Imported by: 0

README

httpc

Go Reference MIT License Go Report Card

A modern, fluent HTTP client library for Go with built-in retry logic, interceptors, and convenience methods.

Features

  • Fluent API: Chainable methods for building requests
  • Retry Logic: Configurable automatic retry with exponential backoff
  • Interceptors: Middleware pattern for request modification (auth, logging, rate limiting, etc.)
  • JSON Support: Built-in JSON marshaling/unmarshaling
  • XML Support: Built-in XML marshaling/unmarshaling
  • Context Support: Full context.Context integration
  • Flexible Configuration: Options pattern for client and request configuration
  • Thread-Safe: Safe for concurrent use
  • HTTP/2 Support: Automatic HTTP/2 with fallback to HTTP/1.1

Installation

go get httpc

Quick Start

Simple GET Request
client := httpc.NewClient()
resp, err := client.Get("https://api.example.com/users")
if err != nil {
    log.Fatal(err)
}

body, err := resp.String()
if err != nil {
    log.Fatal(err)
}
fmt.Println(body)
JSON Request/Response
client := httpc.NewClient(httpc.WithBaseURL("https://api.example.com"))

type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

// POST JSON
user := User{Name: "John", Email: "john@example.com"}
var result User
err := client.PostJSON("/users", user, &result)
if err != nil {
    log.Fatal(err)
}

// GET JSON
var users []User
err = client.GetJSON("/users", &users)
if err != nil {
    log.Fatal(err)
}
XML Request/Response
client := httpc.NewClient(httpc.WithBaseURL("https://api.example.com"))

type Config struct {
    Environment string `xml:"environment"`
    Port        int    `xml:"port"`
}

// POST XML
config := Config{Environment: "production", Port: 8080}
var result Config
err := client.PostXML("/config", config, &result)
if err != nil {
    log.Fatal(err)
}

// GET XML
var settings Config
err = client.GetXML("/config", &settings)
if err != nil {
    log.Fatal(err)
}

Client Configuration

Basic Configuration
client := httpc.NewClient(
    httpc.WithBaseURL("https://api.example.com"),
    httpc.WithTimeout(30 * time.Second),
    httpc.WithHeader("User-Agent", "MyApp/1.0"),
    httpc.WithHeader("Accept", httpc.ContentTypeJSON),
)
With Retry Logic
retryConfig := httpc.DefaultRetryConfig()
retryConfig.MaxRetries = 3
retryConfig.Backoff = time.Second

client := httpc.NewClient(
    httpc.WithBaseURL("https://api.example.com"),
    httpc.WithRetry(retryConfig),
)
With Interceptors
client := httpc.NewClient(
    httpc.WithBaseURL("https://api.example.com"),
    httpc.WithDebug(),
    httpc.WithAuthorization("your-token"),
)

Request Building

Using Request Builder
resp, err := client.NewRequest().
    Method("POST").
    URL("/users").
    Header("Content-Type", httpc.ContentTypeJSON).
    Query("filter", "active").
    JSON(map[string]string{"name": "John"}).
    Do()
Using Convenience Methods
// GET
resp, err := client.Get("/users",
    httpc.Header("Accept", httpc.ContentTypeJSON),
    httpc.WithQuery("page", "1"),
)

// POST
resp, err := client.Post("/users", userData)

// PUT
resp, err := client.Put("/users/123", userData)

// DELETE
resp, err := client.Delete("/users/123")
With Context

All HTTP methods support context for cancellation, timeouts, and deadline propagation:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// All methods have WithContext variants
resp, err := client.GetWithContext(ctx, "/users")
resp, err := client.PostWithContext(ctx, "/users", userData)
resp, err := client.PutWithContext(ctx, "/users/123", userData)
resp, err := client.DeleteWithContext(ctx, "/users/123")
resp, err := client.PatchWithContext(ctx, "/users/123", updates)

// JSON methods also support context
var users []User
err := client.GetJSONWithContext(ctx, "/users", &users)

user := User{Name: "Jane"}
var created User
err = client.PostJSONWithContext(ctx, "/users", user, &created)

// XML methods also support context
var config Config
err = client.GetXMLWithContext(ctx, "/config", &config)

settings := Config{Environment: "staging", Port: 9090}
var settingsResult Config
err = client.PostXMLWithContext(ctx, "/config", settings, &settingsResult)

// Or use WithContext as a RequestOption
resp, err := client.Get("/users",
    httpc.WithContext(ctx),
    httpc.WithQuery("page", "1"),
)

Interceptors

Interceptors allow you to modify requests before they are sent. Several built-in interceptors are provided:

Authentication
// Bearer token
client := httpc.NewClient(
    httpc.WithAuthorization("your-token"),
)

// Basic auth
client := httpc.NewClient(
    httpc.WithBaseAuth("username", "password"),
)

// API Key
client := httpc.NewClient(
    httpc.WithApiKey("X-API-Key", "your-api-key"),
)
User Agent
// Set a custom User-Agent header for all requests
client := httpc.NewClient(
    httpc.WithUserAgent("MyApp/1.0"),
)
Logging
// With default logger
client := httpc.NewClient(
    httpc.WithLogger(log.Default()),
)

// Or with debug mode
client := httpc.NewClient(
    httpc.WithDebug(),
)
Request ID
client := httpc.NewClient(
    httpc.WithRequestId("X-Request-ID"),
)
Custom Headers
client := httpc.NewClient(
    httpc.WithHeaders(map[string]string{
        "X-Custom-Header": "value",
        "X-App-Version":   "1.0",
    }),
)
Domain Blocking
client := httpc.NewClient(
    httpc.WithBlockedList([]string{
        "blocked-domain.com",
        "another-blocked.com",
    }),
)
Custom Interceptor

Interceptors wrap the underlying http.RoundTripper to add custom behavior:

customInterceptor := func(rt http.RoundTripper) http.RoundTripper {
    return &customTransport{transport: rt}
}

type customTransport struct {
    transport http.RoundTripper
}

func (t *customTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    // Modify request
    req = req.Clone(req.Context())
    req.Header.Set("X-Custom", "value")
    return t.transport.RoundTrip(req)
}

client := httpc.NewClient(
    httpc.WithInterceptor(customInterceptor),
)
Dynamic Interceptors

You can also add interceptors after client creation:

client := httpc.NewClient()
// Add logging interceptor dynamically
client.AddInterceptor(func(rt http.RoundTripper) http.RoundTripper {
    return &loggingTransport{
        transport: rt,
        logger:    log.Default(),
    }
})

Response Handling

As Bytes
resp, err := client.Get("/users")
if err != nil {
    log.Fatal(err)
}

body, err := resp.Bytes()
if err != nil {
    log.Fatal(err)
}
As String
resp, err := client.Get("/users")
if err != nil {
    log.Fatal(err)
}

body, err := resp.String()
if err != nil {
    log.Fatal(err)
}
As JSON
type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

resp, err := client.Get("/users/123")
if err != nil {
    log.Fatal(err)
}

var user User
err = resp.JSON(&user)
if err != nil {
    log.Fatal(err)
}
As XML
type Config struct {
    Environment string `xml:"environment"`
    Port        int    `xml:"port"`
}

resp, err := client.Get("/config")
if err != nil {
    log.Fatal(err)
}

var config Config
err = resp.XML(&config)
if err != nil {
    log.Fatal(err)
}
Access Response Metadata
resp, err := client.Get("/users")
if err != nil {
    log.Fatal(err)
}

fmt.Println("Status:", resp.StatusCode)
fmt.Println("Headers:", resp.Header)
fmt.Println("Content-Type:", resp.Header.Get("Content-Type"))

Retry Configuration

Basic Retry
client := httpc.NewClient(
    httpc.WithRetry(httpc.DefaultRetryConfig()),
)

The default retry logic:

  • Retries on any error
  • Retries on 5xx status codes
  • Retries on 429 (rate limit) status code
  • Uses exponential backoff (backoff * attempt)
Custom Retry Logic
retryConfig := &httpc.RetryConfig{
    MaxRetries: 5,
    Backoff:    2 * time.Second,
    RetryIf: func(resp *http.Response, err error) bool {
        // Custom logic
        if err != nil {
            return true
        }
        // Only retry on specific status codes
        return resp.StatusCode == 503 || resp.StatusCode == 504
    },
}

client := httpc.NewClient(
    httpc.WithRetry(retryConfig),
)

Error Handling

HTTP Errors
resp, err := client.Get("/users")
if err != nil {
    // Network error, timeout, etc.
    log.Fatal(err)
}

if !resp.isSuccess() { // Checks if status is 2xx
    // HTTP error (4xx, 5xx)
    body, _ := resp.String()
    log.Printf("HTTP error %d: %s", resp.StatusCode, body)
}
Custom Error Type
resp, err := client.Get("/users")
if err != nil {
    var httpErr *httpc.Error
    if errors.As(err, &httpErr) {
        log.Printf("Status: %d, Message: %s", httpErr.StatusCode, httpErr.Message)
    }
}
Timeout Detection
resp, err := client.Get("/users")
if err != nil {
    if httpc.IsTimeout(err) {
        log.Println("Request timed out")
    }
}

Content Types

Pre-defined content type constants:

httpc.ContentTypeJSON        // application/json
httpc.ContentTypeXML         // application/xml
httpc.ContentTypeForm        // application/x-www-form-urlencoded
httpc.ContentTypeMultipart   // multipart/form-data
httpc.ContentTypePlainText   // text/plain
httpc.ContentTypeHTML        // text/html
httpc.ContentTypeCSV         // text/csv
httpc.ContentTypeJavaScript  // application/javascript
httpc.ContentTypeCSS         // text/css
httpc.ContentTypePDF         // application/pdf
httpc.ContentTypeZip         // application/zip
httpc.ContentTypeOctetStream // application/octet-stream

Advanced Examples

Complete REST API Client
type APIClient struct {
    client *httpc.Client
}

func NewAPIClient(baseURL, token string) *APIClient {
    retryConfig := httpc.DefaultRetryConfig()

    client := httpc.NewClient(
        httpc.WithBaseURL(baseURL),
        httpc.WithTimeout(30*time.Second),
        httpc.WithRetry(*retryConfig),
        httpc.WithAuthorization(token),
        httpc.WithDebug(),
        httpc.WithHeader("Accept", httpc.ContentTypeJSON),
    )

    return &APIClient{client: client}
}

func (a *APIClient) GetUser(id int) (*User, error) {
    var user User
    err := a.client.GetJSON(fmt.Sprintf("/users/%d", id), &user)
    return &user, err
}

func (a *APIClient) CreateUser(user *User) error {
    return a.client.PostJSON("/users", user, user)
}
With Query Parameters
resp, err := client.NewRequest().
    Method("GET").
    URL("/users").
    Query("page", "1").
    Query("limit", "10").
    Query("sort", "name").
    Do()

// Or with multiple parameters at once
resp, err := client.NewRequest().
    Method("GET").
    URL("/users").
    QueryParams(map[string]string{
        "page":  "1",
        "limit": "10",
        "sort":  "name",
    }).
    Do()
With Request Timeout

The Timeout() method sets a request-specific timeout that overrides the client's default timeout. This creates a timeout context that will cancel the request if it exceeds the specified duration.

resp, err := client.NewRequest().
    Method("GET").
    URL("/users").
    Timeout(5 * time.Second).  // Request times out after 5 seconds
    Do()

if httpc.IsTimeout(err) {
    log.Println("Request timed out")
}

Timeout applies to:

  • Connection establishment
  • Request sending
  • Response reading
  • The entire request/response cycle

Combining Timeout with Context:

// You can combine both timeout and custom context
ctx := context.WithValue(context.Background(), "request-id", "123")
resp, err := client.NewRequest().
    Method("GET").
    URL("/users").
    Context(ctx).              // Custom context with values
    Timeout(5 * time.Second).  // Timeout is applied to this context
    Do()
With Custom Body
resp, err := client.NewRequest().
    Method("POST").
    URL("/upload").
    Header("Content-Type", "text/plain").
    Body(strings.NewReader("custom body content")).
    Do()

Transport Configuration

The default transport is configured with:

  • HTTP/2 support with fallback
  • Connection pooling (100 max idle, 10 per host)
  • 30s dial timeout
  • 30s keep-alive
  • 90s idle connection timeout
  • 10s TLS handshake timeout
  • Proxy from environment
  • Compression disabled (for manual control)

Thread Safety

The Client is safe for concurrent use. All methods are thread-safe and can be called from multiple goroutines simultaneously.

Best Practices

  1. Reuse Clients: Create one client and reuse it for multiple requests to benefit from connection pooling
  2. Use Context: Always use context for cancellation and timeouts in production code
  3. Handle Errors: Check both network errors and HTTP status codes
  4. Set Timeouts: Always set appropriate timeouts to prevent hanging requests
  5. Use Interceptors: Centralize cross-cutting concerns like auth, logging, and metrics
  6. Base URL: Use WithBaseURL for APIs to avoid repeating the domain
  7. Retry Logic: Enable retries for transient failures in production environments

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

Documentation

Overview

Package httpc provides HTTP client functionality. This file contains the DebugTransport implementation for detailed request/response logging.

Package httpc provides a modern, fluent HTTP client for Go with support for retry logic, interceptors, and convenient request building.

Features

  • Fluent API with chainable methods for building requests
  • Automatic retry with configurable exponential backoff
  • Interceptor pattern for request modification (auth, logging, rate limiting, etc.)
  • Built-in JSON marshaling and unmarshaling
  • Full context.Context support with cancellation, timeouts, and deadlines
  • All HTTP methods (GET, POST, PUT, DELETE, PATCH) with context variants
  • Thread-safe client that can be used concurrently
  • HTTP/2 support with automatic fallback to HTTP/1.1
  • Connection pooling and keep-alive

Quick Start

Create a client and make a simple GET request:

client := httpc.NewClient()
resp, err := client.Get("https://api.example.com/users")
if err != nil {
	log.Fatal(err)
}
body, _ := resp.String()
fmt.Println(body)

Client Configuration

Configure a client with base URL, timeout, and headers:

retryConfig := httpc.DefaultRetryConfig()
retryConfig.MaxRetries = 3
retryConfig.Backoff = time.Second

client := httpc.NewClient(
	httpc.WithBaseURL("https://api.example.com"),
	httpc.WithTimeout(30*time.Second),
	httpc.WithHeader("User-Agent", "MyApp/1.0"),
	httpc.WithRetry(*retryConfig),
)

JSON Requests

Send and receive JSON easily:

type User struct {
	Name  string `json:"name"`
	Email string `json:"email"`
}

user := User{Name: "John", Email: "john@example.com"}
var result User
err := client.PostJSON("/users", user, &result)

Request Builder

Use the fluent request builder for complex requests:

resp, err := client.NewRequest().
	Method("POST").
	URL("/api/users").
	Header("Authorization", "Bearer token").
	Query("include", "profile").
	JSON(userData).
	Timeout(10*time.Second).
	Do()

Interceptors

Add interceptors for cross-cutting concerns:

client := httpc.NewClient(
	httpc.WithDebug(),
	httpc.WithAuthorization("your-token"),
	httpc.WithLogger(log.Default()),
)

Available built-in options:

  • WithAuthorization(token): Bearer token authentication
  • WithBaseAuth(user, pass): HTTP Basic authentication
  • WithApiKey(header, key): API key authentication
  • WithUserAgent(ua): Sets User-Agent header
  • WithRequestId(header): Adds unique request IDs
  • WithLogger(logger): Request/response logging
  • WithDebug(): Debug mode with detailed logging
  • WithBlockedList(domains): Blocks requests to specific domains
  • WithHeaders(map): Adds custom headers

Custom interceptors wrap the underlying http.RoundTripper:

customInterceptor := func(rt http.RoundTripper) http.RoundTripper {
	return &customTransport{transport: rt}
}
client := httpc.NewClient(httpc.WithInterceptor(customInterceptor))

Retry Logic

Configure automatic retries with exponential backoff:

retryConfig := httpc.DefaultRetryConfig()
retryConfig.MaxRetries = 3
retryConfig.Backoff = time.Second

client := httpc.NewClient(
	httpc.WithRetry(*retryConfig),
)

By default, requests are retried on:

  • Network errors and timeouts
  • 5xx server errors
  • 429 (rate limit) responses

Error Handling

Check for both network errors and HTTP errors:

resp, err := client.Get("/api/users")
if err != nil {
	if httpc.IsTimeout(err) {
		log.Println("Request timed out")
	}
	log.Fatal(err)
}

if resp.StatusCode >= 400 {
	log.Printf("HTTP error: %d", resp.StatusCode)
}

Context Support

All HTTP methods support context for cancellation, timeouts, and deadlines:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// All methods have WithContext variants
resp, err := client.GetWithContext(ctx, "/api/users")
resp, err := client.PostWithContext(ctx, "/api/users", userData)
resp, err := client.PutWithContext(ctx, "/api/users/123", userData)
resp, err := client.DeleteWithContext(ctx, "/api/users/123")
resp, err := client.PatchWithContext(ctx, "/api/users/123", updates)

// JSON methods also support context
var users []User
err := client.GetJSONWithContext(ctx, "/api/users", &users)

Or use the request builder:

resp, err := client.NewRequest().
	Method("GET").
	URL("/api/users").
	Context(ctx).
	Timeout(5*time.Second).  // Timeout wraps the context
	Do()

Or pass context as a RequestOption:

resp, err := client.Get("/api/users",
	httpc.WithContext(ctx),
	httpc.WithQuery("page", "1"),
)

Content Types

The package provides constants for common content types:

httpc.ContentTypeJSON        // application/json
httpc.ContentTypeXML         // application/xml
httpc.ContentTypeForm        // application/x-www-form-urlencoded
httpc.ContentTypePlainText   // text/plain
httpc.ContentTypeHTML        // text/html
// ... and more

Thread Safety

The Client is safe for concurrent use. You should create one client and reuse it for multiple requests to benefit from connection pooling:

// Create once, use many times from different goroutines
client := httpc.NewClient()

go func() {
	resp, _ := client.Get("/api/endpoint1")
	// ...
}()

go func() {
	resp, _ := client.Get("/api/endpoint2")
	// ...
}()

Best Practices

  • Reuse clients to benefit from connection pooling
  • Always use contexts for production code
  • Set appropriate timeouts to prevent hanging requests
  • Enable retry logic for transient failures
  • Use interceptors to centralize cross-cutting concerns
  • Check both error return values and HTTP status codes

Package httpc provides HTTP client functionality. This file defines the Interceptor type for wrapping http.RoundTripper implementations.

Package httpc provides HTTP client functionality. This file contains various http.RoundTripper implementations for features like headers, authentication, retry logic, logging, and request blocking.

Example

Example demonstrates basic usage of the HTTP client.

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/mam-coder/httpc"
)

func main() {
	client := httpc.NewClient(
		httpc.WithBaseURL("https://api.example.com"),
		httpc.WithTimeout(10*time.Second),
	)

	resp, err := client.Get("/users")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Status:", resp.StatusCode)
}

Index

Examples

Constants

View Source
const (
	// ContentTypeJSON represents JSON content (application/json)
	ContentTypeJSON = "application/json"

	// ContentTypeXML represents XML content (application/xml)
	ContentTypeXML = "application/xml"

	// ContentTypeForm represents URL-encoded form data (application/x-www-form-urlencoded)
	ContentTypeForm = "application/x-www-form-urlencoded"

	// ContentTypeMultipart represents multipart form data (multipart/form-data)
	ContentTypeMultipart = "multipart/form-data"

	// ContentTypePlainText represents plain text content (text/plain)
	ContentTypePlainText = "text/plain"

	// ContentTypeHTML represents HTML content (text/html)
	ContentTypeHTML = "text/html"

	// ContentTypeCSV represents CSV content (text/csv)
	ContentTypeCSV = "text/csv"

	// ContentTypeApplicationCSV represents CSV content (application/csv)
	ContentTypeApplicationCSV = "application/csv"

	// ContentTypeJavaScript represents JavaScript content (application/javascript)
	ContentTypeJavaScript = "application/javascript"

	// ContentTypeCSS represents CSS content (text/css)
	ContentTypeCSS = "text/css"

	// ContentTypePDF represents PDF content (application/pdf)
	ContentTypePDF = "application/pdf"

	// ContentTypeZip represents ZIP archive content (application/zip)
	ContentTypeZip = "application/zip"

	// ContentTypeOctetStream represents arbitrary binary data (application/octet-stream)
	ContentTypeOctetStream = "application/octet-stream"
)

Common Content-Type header values for HTTP requests and responses.

Variables

This section is empty.

Functions

func IsTimeout

func IsTimeout(err error) bool

IsTimeout checks if the error is a timeout error. It returns true if the error is either a net.Error with Timeout() == true or a context.DeadlineExceeded error.

Example:

resp, err := client.Get("/api/slow-endpoint")
if httpc.IsTimeout(err) {
	log.Println("Request timed out")
}
Example

ExampleIsTimeout demonstrates checking for timeout errors.

package main

import (
	"fmt"
	"time"

	"github.com/mam-coder/httpc"
)

func main() {
	client := httpc.NewClient(
		httpc.WithTimeout(1 * time.Millisecond),
	)

	_, err := client.Get("https://example.com/slow-endpoint")
	if httpc.IsTimeout(err) {
		fmt.Println("Request timed out")
	}
}

Types

type Client

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

Client is the main HTTP client type that provides a fluent API for making HTTP requests. It supports configuration through options, automatic retries, request interceptors, and various convenience methods for common HTTP operations.

Client is safe for concurrent use by multiple goroutines.

func Default

func Default() *Client

Default creates a client with sensible defaults. This is equivalent to calling NewClient() with no options. The returned client will have a 30-second timeout and standard transport settings.

Example:

client := httpc.Default()
resp, err := client.Get("https://api.example.com/users")

func NewClient

func NewClient(opts ...Option) *Client

NewClient creates a new HTTP client with the specified options. Options can configure the base URL, timeout, headers, retry logic, interceptors, and other client behavior.

Available options:

  • WithBaseURL: Set base URL for all requests
  • WithTimeout: Set request timeout duration
  • WithHeader: Add a single header to all requests
  • WithHeaders: Add multiple headers to all requests
  • WithUserAgent: Set User-Agent header
  • WithContentType: Set Content-Type header
  • WithAccept: Set Accept header
  • WithAuthorization: Add Bearer token authentication
  • WithBaseAuth: Add HTTP Basic authentication
  • WithApiKey: Add API key authentication
  • WithRequestId: Add unique request ID header
  • WithRetry: Configure automatic retry logic
  • WithLogger: Add request/response logging
  • WithDebug: Enable debug mode
  • WithBlockedList: Block requests to specific domains
  • WithInterceptor: Add custom request/response interceptor

Example:

client := httpc.NewClient(
	httpc.WithBaseURL("https://api.example.com"),
	httpc.WithTimeout(30*time.Second),
	httpc.WithHeader("User-Agent", "MyApp/1.0"),
)
Example

ExampleNewClient demonstrates creating a new HTTP client with options.

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/mam-coder/httpc"
)

func main() {
	client := httpc.NewClient(
		httpc.WithBaseURL("https://api.example.com"),
		httpc.WithTimeout(30*time.Second),
		httpc.WithHeader("User-Agent", "MyApp/1.0"),
	)

	resp, err := client.Get("/users")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Response received:", resp.StatusCode >= 200 && resp.StatusCode < 300)
}

func (*Client) Delete

func (c *Client) Delete(url string, opts ...RequestOption) (*Response, error)

Delete sends an HTTP DELETE request to the specified URL.

Example:

resp, err := client.Delete("/api/users/123")

func (*Client) DeleteWithContext

func (c *Client) DeleteWithContext(ctx context.Context, url string, opts ...RequestOption) (*Response, error)

DeleteWithContext sends an HTTP DELETE request with a context. The context can be used for cancellation or setting deadlines.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.DeleteWithContext(ctx, "/api/users/123")

func (*Client) Get

func (c *Client) Get(url string, opts ...RequestOption) (*Response, error)

Get sends an HTTP GET request to the specified URL. Optional RequestOption functions can be provided to customize the request.

Example:

resp, err := client.Get("/api/users",
    httpc.Header("Accept", httpc.ContentTypeJSON),
    httpc.WithQuery("page", "1"),
)
Example

ExampleClient_Get demonstrates making a GET request.

package main

import (
	"fmt"
	"log"

	"github.com/mam-coder/httpc"
)

func main() {
	client := httpc.NewClient(
		httpc.WithBaseURL("https://api.example.com"),
	)

	resp, err := client.Get("/users",
		httpc.WithQuery("page", "1"),
		httpc.WithQuery("limit", "10"),
	)
	if err != nil {
		log.Fatal(err)
	}

	body, _ := resp.String()
	fmt.Println("Response:", len(body) > 0)
}

func (*Client) GetCSV added in v1.0.1

func (c *Client) GetCSV(url string, result interface{}, opts ...RequestOption) error

GetCSV is a convenience method that sends a GET request and automatically unmarshals the CSV response into the result parameter. The result must be a pointer to a slice of structs.

Example:

type User struct {
	ID   string `csv:"id"`
	Name string `csv:"name"`
}

var users []User
err := client.GetCSV("/api/users.csv", &users,
    httpc.WithQuery("status", "active"),
)

func (*Client) GetCSVWithContext added in v1.0.1

func (c *Client) GetCSVWithContext(ctx context.Context, url string, result interface{}, opts ...RequestOption) error

GetCSVWithContext is a convenience method that sends a GET request with a context and automatically unmarshals the CSV response into the result parameter. The result must be a pointer to a slice of structs.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

type User struct {
	ID   string `csv:"id"`
	Name string `csv:"name"`
}

var users []User
err := client.GetCSVWithContext(ctx, "/api/users.csv", &users,
    httpc.WithQuery("status", "active"),
)

func (*Client) GetCSVWithSeparator added in v1.0.1

func (c *Client) GetCSVWithSeparator(url string, separator rune, result interface{}, opts ...RequestOption) error

GetCSVWithSeparator is a convenience method that sends a GET request and automatically unmarshals the CSV response using a custom separator into the result parameter. This is useful for TSV files or other delimited formats. The result must be a pointer to a slice of structs.

Example:

type User struct {
	ID   string `csv:"id"`
	Name string `csv:"name"`
}

var users []User
err := client.GetCSVWithSeparator("/api/users.tsv", '\t', &users,
    httpc.WithQuery("status", "active"),
)

func (*Client) GetCSVWithSeparatorAndContext added in v1.0.1

func (c *Client) GetCSVWithSeparatorAndContext(ctx context.Context, url string, separator rune, result interface{}, opts ...RequestOption) error

GetCSVWithSeparatorAndContext is a convenience method that sends a GET request with a context and automatically unmarshals the CSV response using a custom separator into the result parameter. This is useful for TSV files or other delimited formats. The result must be a pointer to a slice of structs.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

type User struct {
	ID   string `csv:"id"`
	Name string `csv:"name"`
}

var users []User
err := client.GetCSVWithSeparatorAndContext(ctx, "/api/users.tsv", '\t', &users,
    httpc.WithQuery("status", "active"),
)

func (*Client) GetJSON

func (c *Client) GetJSON(url string, result interface{}, opts ...RequestOption) error

GetJSON is a convenience method that sends a GET request and automatically unmarshals the JSON response into the result parameter.

Example:

var users []User
err := client.GetJSON("/api/users", &users,
    httpc.WithQuery("status", "active"),
)
Example

ExampleClient_GetJSON demonstrates getting and parsing JSON response.

package main

import (
	"fmt"
	"log"

	"github.com/mam-coder/httpc"
)

func main() {
	client := httpc.NewClient(
		httpc.WithBaseURL("https://api.example.com"),
	)

	var users []map[string]interface{}
	err := client.GetJSON("/users", &users)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Got users:", len(users) >= 0)
}

func (*Client) GetJSONWithContext

func (c *Client) GetJSONWithContext(ctx context.Context, url string, result interface{}, opts ...RequestOption) error

GetJSONWithContext is a convenience method that sends a GET request with a context and automatically unmarshals the JSON response into the result parameter.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var users []User
err := client.GetJSONWithContext(ctx, "/api/users", &users,
    httpc.WithQuery("status", "active"),
)

func (*Client) GetWithContext

func (c *Client) GetWithContext(ctx context.Context, url string, opts ...RequestOption) (*Response, error)

GetWithContext sends an HTTP GET request with a context. The context can be used for cancellation or setting deadlines.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.GetWithContext(ctx, "/api/users")

func (*Client) GetXML added in v1.0.1

func (c *Client) GetXML(url string, result interface{}, opts ...RequestOption) error

GetXML is a convenience method that sends a GET request and automatically unmarshals the XML response into the result parameter.

Example:

var config Config
err := client.GetXML("/api/config", &config,
    httpc.WithQuery("env", "production"),
)

func (*Client) GetXMLWithContext added in v1.0.1

func (c *Client) GetXMLWithContext(ctx context.Context, url string, result interface{}, opts ...RequestOption) error

GetXMLWithContext is a convenience method that sends a GET request with a context and automatically unmarshals the XML response into the result parameter.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var config Config
err := client.GetXMLWithContext(ctx, "/api/config", &config,
    httpc.WithQuery("env", "production"),
)

func (*Client) NewRequest

func (c *Client) NewRequest() *RequestBuilder

NewRequest creates a new RequestBuilder for building and executing HTTP requests.

Example:

rb := client.NewRequest()
resp, err := rb.Method("GET").URL("/api/users").Do()
Example

ExampleClient_NewRequest demonstrates using the request builder.

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/mam-coder/httpc"
)

func main() {
	client := httpc.NewClient()

	resp, err := client.NewRequest().
		Method("POST").
		URL("https://api.example.com/users").
		Header("Authorization", "Bearer token").
		Query("include", "profile").
		JSON(map[string]string{"name": "John"}).
		Timeout(5 * time.Second).
		Do()

	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Request completed:", resp != nil)
}

func (*Client) Patch

func (c *Client) Patch(url string, body interface{}, opts ...RequestOption) (*Response, error)

Patch sends an HTTP PATCH request with a JSON body to the specified URL. The body is automatically marshaled to JSON and the Content-Type header is set. Pass nil for body if no request body is needed.

Example:

updates := map[string]string{"status": "active"}
resp, err := client.Patch("/api/users/123", updates)

func (*Client) PatchWithContext

func (c *Client) PatchWithContext(ctx context.Context, url string, body interface{}, opts ...RequestOption) (*Response, error)

PatchWithContext sends an HTTP PATCH request with a context and JSON body. The context can be used for cancellation or setting deadlines.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.PatchWithContext(ctx, "/api/users/123", updates)

func (*Client) Post

func (c *Client) Post(url string, body interface{}, opts ...RequestOption) (*Response, error)

Post sends an HTTP POST request with a JSON body to the specified URL. The body is automatically marshaled to JSON and the Content-Type header is set. Pass nil for body if no request body is needed.

Example:

user := map[string]string{"name": "John", "email": "john@example.com"}
resp, err := client.Post("/api/users", user)
Example

ExampleClient_Post demonstrates making a POST request with JSON.

package main

import (
	"fmt"
	"log"

	"github.com/mam-coder/httpc"
)

func main() {
	client := httpc.NewClient(
		httpc.WithBaseURL("https://api.example.com"),
	)

	user := map[string]string{
		"name":  "John Doe",
		"email": "john@example.com",
	}

	resp, err := client.Post("/users", user)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Created:", resp.StatusCode == 201)
}

func (*Client) PostJSON

func (c *Client) PostJSON(url string, body interface{}, result interface{}, opts ...RequestOption) error

PostJSON is a convenience method that sends a POST request with a JSON body and automatically unmarshals the JSON response into the result parameter. Pass nil for result if you don't need to parse the response.

Example:

user := User{Name: "John", Email: "john@example.com"}
var created User
err := client.PostJSON("/api/users", user, &created)

func (*Client) PostJSONWithContext

func (c *Client) PostJSONWithContext(ctx context.Context, url string, body interface{}, result interface{}, opts ...RequestOption) error

PostJSONWithContext is a convenience method that sends a POST request with a context, JSON body, and automatically unmarshals the JSON response into the result parameter. Pass nil for result if you don't need to parse the response.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
user := User{Name: "John", Email: "john@example.com"}
var created User
err := client.PostJSONWithContext(ctx, "/api/users", user, &created)

func (*Client) PostWithContext

func (c *Client) PostWithContext(ctx context.Context, url string, body interface{}, opts ...RequestOption) (*Response, error)

PostWithContext sends an HTTP POST request with a context and JSON body. The context can be used for cancellation or setting deadlines.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.PostWithContext(ctx, "/api/users", userData)

func (*Client) PostXML added in v1.0.1

func (c *Client) PostXML(url string, body interface{}, result interface{}, opts ...RequestOption) error

PostXML is a convenience method that sends a POST request with an XML body and automatically unmarshals the XML response into the result parameter. Pass nil for result if you don't need to parse the response.

Example:

config := Config{Environment: "production"}
var created Config
err := client.PostXML("/api/config", config, &created)

func (*Client) PostXMLWithContext added in v1.0.1

func (c *Client) PostXMLWithContext(ctx context.Context, url string, body interface{}, result interface{}, opts ...RequestOption) error

PostXMLWithContext is a convenience method that sends a POST request with a context, XML body, and automatically unmarshals the XML response into the result parameter. Pass nil for result if you don't need to parse the response.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
config := Config{Environment: "production"}
var created Config
err := client.PostXMLWithContext(ctx, "/api/config", config, &created)

func (*Client) Put

func (c *Client) Put(url string, body interface{}, opts ...RequestOption) (*Response, error)

Put sends an HTTP PUT request with a JSON body to the specified URL. The body is automatically marshaled to JSON and the Content-Type header is set. Pass nil for body if no request body is needed.

Example:

user := map[string]string{"name": "John Doe"}
resp, err := client.Put("/api/users/123", user)

func (*Client) PutWithContext

func (c *Client) PutWithContext(ctx context.Context, url string, body interface{}, opts ...RequestOption) (*Response, error)

PutWithContext sends an HTTP PUT request with a context and JSON body. The context can be used for cancellation or setting deadlines.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.PutWithContext(ctx, "/api/users/123", userData)

type DebugTransport

type DebugTransport struct {
	Debug       bool
	Logger      *log.Logger
	LogBody     bool
	MaxBodySize int64
	// contains filtered or unexported fields
}

DebugTransport is a wrapper around http.DefaultTransport that logs HTTP requests and responses.

func NewDebugTransport

func NewDebugTransport(transport http.RoundTripper, debug bool) *DebugTransport

func (*DebugTransport) RoundTrip

func (t *DebugTransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements the http.RoundTripper interface for DebugTransport. It logs the request and response and delegates to the underlying RoundTripper.

type Error

type Error struct {
	// StatusCode is the HTTP status code returned by the server
	StatusCode int

	// Message is a human-readable error message
	Message string

	// Body is the raw response body from the server
	Body []byte
}

Error represents an HTTP error response from the client. It contains the HTTP status code, error message, and response body.

Example:

resp, err := client.Get("/api/users")
if err != nil {
	var httpErr *httpc.Error
	if errors.As(err, &httpErr) {
		fmt.Printf("Status: %d, Message: %s\n", httpErr.StatusCode, httpErr.Message)
	}
}

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface and returns a formatted error message containing the status code and message.

type Interceptor

type Interceptor func(tripper http.RoundTripper) http.RoundTripper

Interceptor is a function that wraps an http.RoundTripper to add custom behavior. Interceptors can be chained together to create complex request/response processing pipelines.

Example:

customInterceptor := func(rt http.RoundTripper) http.RoundTripper {
    return &myCustomTransport{transport: rt}
}
client := httpc.NewClient(httpc.WithInterceptor(customInterceptor))

type Option

type Option func(*Client)

Option is a function that configures a Client. Options are passed to NewClient to customize client behavior such as setting timeouts, base URLs, headers, retry logic, and interceptors.

Example with multiple options:

client := httpc.NewClient(
	httpc.WithBaseURL("https://api.example.com"),
	httpc.WithTimeout(30*time.Second),
	httpc.WithHeader("User-Agent", "MyApp/1.0"),
	httpc.WithAuthorization("your-api-token"),
	httpc.WithDebug(),
)

func WithAccept

func WithAccept(accept string) Option

WithAccept sets the Accept header for all requests.

Example:

client := httpc.NewClient(httpc.WithAccept(httpc.ContentTypeJSON))

func WithApiKey

func WithApiKey(headerName, apiKey string) Option

WithApiKey sets an API key header for authentication. If headerName is empty, defaults to "X-Api-Key".

Example:

client := httpc.NewClient(httpc.WithApiKey("X-API-Key", "secret-key-123"))
// Or with default header name:
client := httpc.NewClient(httpc.WithApiKey("", "secret-key-123"))

func WithAuthorization

func WithAuthorization(token string) Option

WithAuthorization sets a Bearer token for authentication. The token is added to the Authorization header as "Bearer <token>".

Example:

client := httpc.NewClient(httpc.WithAuthorization("your-api-token"))
Example

ExampleWithAuthorization demonstrates Bearer token authentication.

package main

import (
	"fmt"
	"log"

	"github.com/mam-coder/httpc"
)

func main() {
	client := httpc.NewClient(
		httpc.WithBaseURL("https://api.example.com"),
		httpc.WithAuthorization("your-api-token"),
	)

	resp, err := client.Get("/protected/resource")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Authenticated:", resp.StatusCode != 401)
}

func WithBaseAuth

func WithBaseAuth(username, password string) Option

WithBaseAuth configures HTTP Basic Authentication for all requests. The username and password are automatically encoded and added to the Authorization header.

Example:

client := httpc.NewClient(httpc.WithBaseAuth("user", "password"))
Example

ExampleWithBaseAuth demonstrates HTTP Basic authentication.

package main

import (
	"fmt"
	"log"

	"github.com/mam-coder/httpc"
)

func main() {
	client := httpc.NewClient(
		httpc.WithBaseURL("https://api.example.com"),
		httpc.WithBaseAuth("username", "password"),
	)

	resp, err := client.Get("/protected/resource")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Authenticated:", resp.StatusCode != 401)
}

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL sets the base URL for all requests made by the client. Relative URLs in requests will be resolved against this base URL. If a request uses an absolute URL (starting with http:// or https://), the base URL is ignored for that request.

Example:

client := httpc.NewClient(httpc.WithBaseURL("https://api.example.com"))
resp, err := client.Get("/users")  // Goes to https://api.example.com/users

func WithBlockedList

func WithBlockedList(blockedList []string) Option

WithBlockedList configures a list of domains that should be blocked. Requests to any domain in the blockedList will fail with an error. This is useful for preventing requests to known malicious or unwanted domains.

Example:

client := httpc.NewClient(httpc.WithBlockedList([]string{
	"malicious-site.com",
	"blocked-domain.com",
}))

// Attempting to access a blocked domain will return an error
resp, err := client.Get("https://malicious-site.com/api/data")
if err != nil {
	fmt.Println(err)
	// Output: request to blocked domain: malicious-site.com
}

func WithContentType

func WithContentType(contentType string) Option

WithContentType sets the Content-Type header for all requests.

Example:

client := httpc.NewClient(httpc.WithContentType(httpc.ContentTypeJSON))

func WithDebug

func WithDebug() Option

WithDebug enables debug logging for the client. When enabled, the client will log detailed information about requests and responses.

Example:

client := httpc.NewClient(httpc.WithDebug())

func WithHeader

func WithHeader(key, value string) Option

WithHeader sets a single HTTP header that will be added to every request. Multiple calls to WithHeader will add multiple headers.

Example:

client := httpc.NewClient(
    httpc.WithHeader("User-Agent", "MyApp/1.0"),
    httpc.WithHeader("Accept", "application/json"),
)

func WithHeaders

func WithHeaders(headers map[string]string) Option

WithHeaders sets multiple HTTP headers that will be added to every request. Headers set here can be overridden on a per-request basis.

Example:

client := httpc.NewClient(httpc.WithHeaders(map[string]string{
    "X-App-Version": "1.0",
    "X-Environment": "production",
}))

func WithInterceptor

func WithInterceptor(interceptor Interceptor) Option

WithInterceptor adds a request interceptor to the client. Interceptors are executed in the order they are added and can modify requests before they are sent or return errors to prevent execution. Multiple interceptors can be added by calling this option multiple times.

Example of adding custom headers to all requests:

customHeaderInterceptor := func(rt http.RoundTripper) http.RoundTripper {
	return &customHeaderTransport{transport: rt}
}

type customHeaderTransport struct {
	transport http.RoundTripper
}

func (t *customHeaderTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	req.Header.Set("X-Custom-Header", "MyValue")
	req.Header.Set("X-Request-Time", time.Now().Format(time.RFC3339))
	return t.transport.RoundTrip(req)
}

client := httpc.NewClient(httpc.WithInterceptor(customHeaderInterceptor))

Example of request/response timing interceptor:

timingInterceptor := func(rt http.RoundTripper) http.RoundTripper {
	return roundTripFunc(func(req *http.Request) (*http.Response, error) {
		start := time.Now()
		resp, err := rt.RoundTrip(req)
		duration := time.Since(start)
		log.Printf("%s %s took %v", req.Method, req.URL, duration)
		return resp, err
	})
}

client := httpc.NewClient(httpc.WithInterceptor(timingInterceptor))

Example of conditional request modifier:

conditionalInterceptor := func(rt http.RoundTripper) http.RoundTripper {
	return roundTripFunc(func(req *http.Request) (*http.Response, error) {
		// Add API version header only for specific paths
		if strings.HasPrefix(req.URL.Path, "/api/v2") {
			req.Header.Set("X-API-Version", "2.0")
		}
		return rt.RoundTrip(req)
	})
}

client := httpc.NewClient(httpc.WithInterceptor(conditionalInterceptor))

func WithLogger

func WithLogger(logger *log.Logger) Option

WithLogger configures request/response logging using the provided logger. All HTTP requests and responses will be logged with method, URL, status code, and timing.

Example:

logger := log.New(os.Stdout, "[HTTP] ", log.LstdFlags)
client := httpc.NewClient(httpc.WithLogger(logger))

func WithRequestId

func WithRequestId(headerName string) Option

WithRequestId generates and sets a unique request ID header for tracing. If headerName is empty, defaults to "X-Request-Id". A new request ID is generated for each client instance.

Example:

client := httpc.NewClient(httpc.WithRequestId("X-Request-ID"))

func WithRetry

func WithRetry(config RetryConfig) Option

WithRetry configures automatic retry logic with exponential backoff. Use RetryConfig to specify max retries, backoff duration, and retry conditions.

Example with default retry condition:

config := httpc.RetryConfig{
	MaxRetries: 3,
	Backoff:    time.Second,
	RetryIf:    httpc.DefaultRetryCondition,
}
client := httpc.NewClient(httpc.WithRetry(config))

Example with custom retry condition:

customRetryCondition := func(resp *http.Response, err error) bool {
	// Retry on network errors
	if err != nil {
		return true
	}
	// Retry on specific status codes
	if resp.StatusCode == 429 || resp.StatusCode == 503 {
		return true
	}
	// Retry on 500 errors only if response contains specific message
	if resp.StatusCode == 500 {
		body, _ := io.ReadAll(resp.Body)
		resp.Body = io.NopCloser(bytes.NewReader(body))
		return strings.Contains(string(body), "temporary")
	}
	return false
}

config := httpc.RetryConfig{
	MaxRetries: 5,
	Backoff:    2 * time.Second,
	RetryIf:    customRetryCondition,
}
client := httpc.NewClient(httpc.WithRetry(config))
Example

ExampleWithRetry demonstrates configuring retry logic.

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/mam-coder/httpc"
)

func main() {
	config := httpc.DefaultRetryConfig()
	config.MaxRetries = 3
	config.Backoff = time.Second

	client := httpc.NewClient(
		httpc.WithBaseURL("https://api.example.com"),
		httpc.WithRetry(*config),
	)

	resp, err := client.Get("/users")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Success:", resp.StatusCode == 200)
}

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout sets the request timeout for all requests made by the client. Individual requests can override this timeout using the RequestBuilder.Timeout method. The default timeout is 30 seconds.

Example:

client := httpc.NewClient(httpc.WithTimeout(10*time.Second))

func WithUserAgent

func WithUserAgent(userAgent string) Option

WithUserAgent sets the User-Agent header for all requests.

Example:

client := httpc.NewClient(httpc.WithUserAgent("MyApp/1.0"))

type RequestBuilder

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

RequestBuilder provides a fluent interface for building HTTP requests. It allows chaining method calls to configure all aspects of an HTTP request before executing it with Do().

Example:

resp, err := client.NewRequest().
    Method("POST").
    URL("/api/users").
    Header("Authorization", "Bearer token").
    Query("include", "profile").
    JSON(userData).
    Timeout(10*time.Second).
    Do()

func (*RequestBuilder) Body

func (rb *RequestBuilder) Body(body io.Reader) *RequestBuilder

Body sets the request body from an io.Reader. For JSON bodies, use the JSON() method instead.

Example:

rb.Body(strings.NewReader("plain text body"))

func (*RequestBuilder) Context

func (rb *RequestBuilder) Context(ctx context.Context) *RequestBuilder

Context sets the context for the request, allowing for cancellation and deadlines.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
rb.Context(ctx)

func (*RequestBuilder) Do

func (rb *RequestBuilder) Do() (*Response, error)

Do executes the HTTP request and returns the response. This should be called as the final method in the RequestBuilder chain. Any errors that occurred during request building will be returned here.

Example:

resp, err := client.NewRequest().
    Method("GET").
    URL("/api/users").
    Do()

func (*RequestBuilder) Header

func (rb *RequestBuilder) Header(key, value string) *RequestBuilder

Header adds a header to the request. Can be called multiple times to add multiple headers.

Example:

rb.Header("Authorization", "Bearer token").
   Header("Accept", httpc.ContentTypeJSON)

func (*RequestBuilder) JSON

func (rb *RequestBuilder) JSON(v interface{}) *RequestBuilder

JSON marshals the provided value to JSON and sets it as the request body. It automatically sets the Content-Type header to application/json.

Example:

client.NewRequest().
    Method("POST").
    URL("/api/users").
    JSON(map[string]string{"name": "John"}).
    Do()

func (*RequestBuilder) Method

func (rb *RequestBuilder) Method(method string) *RequestBuilder

Method sets the HTTP method for the request (GET, POST, PUT, DELETE, PATCH, etc.).

Example:

rb.Method("POST")

func (*RequestBuilder) Query

func (rb *RequestBuilder) Query(key, value string) *RequestBuilder

Query adds a query parameter to the request. Can be called multiple times. Values with the same key will be appended (e.g., ?tag=a&tag=b).

Example:

rb.Query("page", "1").Query("limit", "10")

func (*RequestBuilder) QueryParams

func (rb *RequestBuilder) QueryParams(params map[string]string) *RequestBuilder

QueryParams adds multiple query parameters from a map. Each key-value pair will be set (replacing any existing values for those keys).

Example:

rb.QueryParams(map[string]string{
    "page": "1",
    "limit": "10",
    "sort": "name",
})

func (*RequestBuilder) Timeout

func (rb *RequestBuilder) Timeout(timeout time.Duration) *RequestBuilder

Timeout sets a request-specific timeout, overriding the client's default timeout. This creates a timeout context that will cancel the request if it exceeds the duration. The timeout applies to the entire request/response cycle, including connection time, redirects, and reading the response body.

Example:

rb.Timeout(5 * time.Second)

func (*RequestBuilder) URL

func (rb *RequestBuilder) URL(url string) *RequestBuilder

URL sets the request URL. Can be absolute or relative to the client's base URL.

Example:

rb.URL("/api/users") // Relative to base URL
rb.URL("https://api.example.com/users") // Absolute URL

func (*RequestBuilder) XML added in v1.0.1

func (rb *RequestBuilder) XML(v interface{}) *RequestBuilder

XML marshals the provided value to XML and sets it as the request body. It automatically sets the Content-Type header to application/xml.

Example:

client.NewRequest().
    Method("POST").
    URL("/api/config").
    XML(map[string]string{"key": "value"}).
    Do()

type RequestOption

type RequestOption func(*RequestBuilder)

RequestOption is a function that configures a RequestBuilder. It allows customizing individual requests with headers, query parameters, etc.

func Header(key, value string) RequestOption

Header returns a RequestOption that adds a header to the request.

Example:

resp, err := client.Get("/api/users",
    httpc.Header("Authorization", "Bearer token"),
    httpc.Header("Accept", httpc.ContentTypeJSON),
)

func WithContext

func WithContext(ctx context.Context) RequestOption

WithContext returns a RequestOption that sets the context for the request. This is useful when you want to pass a context along with other request options.

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.Get("/api/users",
    httpc.WithContext(ctx),
    httpc.WithQuery("page", "1"),
)

func WithQuery

func WithQuery(key, value string) RequestOption

WithQuery returns a RequestOption that adds a query parameter to the request.

Example:

resp, err := client.Get("/api/users",
    httpc.WithQuery("page", "1"),
    httpc.WithQuery("limit", "10"),
)

type Response

type Response struct {
	*http.Response
	// contains filtered or unexported fields
}

Response wraps http.Response and provides convenience methods for reading and parsing the response body. The body is cached after the first read, so multiple calls to Bytes(), String(), or JSON() will return the same data without re-reading.

func (*Response) Bytes

func (r *Response) Bytes() ([]byte, error)

Bytes returns the response body as a byte slice. The body is read and cached on the first call, subsequent calls return the cached data without re-reading from the network.

Example:

resp, err := client.Get("/api/users")
if err != nil {
	log.Fatal(err)
}
body, err := resp.Bytes()
if err != nil {
	log.Fatal(err)
}

func (*Response) CSV added in v1.0.1

func (r *Response) CSV(v interface{}) error

CSV unmarshals the response body into the provided slice of structs. The first row is expected to contain header names that match struct field names or csv tags. The body is read and cached on the first call. By default, comma (,) is used as the separator. Use SetCSVSeparator to change it.

Example:

type User struct {
	ID   string `csv:"id"`
	Name string `csv:"name"`
}

resp, err := client.Get("/api/users.csv")
if err != nil {
	log.Fatal(err)
}
var users []User
if err := resp.CSV(&users); err != nil {
	log.Fatal(err)
}

func (*Response) JSON

func (r *Response) JSON(v interface{}) error

JSON unmarshals the response body into the provided value. The body is read and cached on the first call.

Example:

type User struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

resp, err := client.Get("/api/users/123")
if err != nil {
	log.Fatal(err)
}
var user User
if err := resp.JSON(&user); err != nil {
	log.Fatal(err)
}

func (*Response) SetCSVSeparator added in v1.0.1

func (r *Response) SetCSVSeparator(sep rune) *Response

SetCSVSeparator sets the separator (delimiter) for CSV parsing. The default separator is comma (,). Use this method to parse TSV files (tab-separated) or other delimited formats.

Example:

resp, err := client.Get("/api/users.tsv")
if err != nil {
	log.Fatal(err)
}
resp.SetCSVSeparator('\t') // Set tab as separator
var users []User
if err := resp.CSV(&users); err != nil {
	log.Fatal(err)
}

func (*Response) String

func (r *Response) String() (string, error)

String returns the response body as a string. The body is read and cached on the first call, subsequent calls return the cached data without re-reading from the network.

Example:

resp, err := client.Get("/api/status")
if err != nil {
	log.Fatal(err)
}
body, err := resp.String()
if err != nil {
	log.Fatal(err)
}
fmt.Println(body)

func (*Response) XML added in v1.0.1

func (r *Response) XML(v interface{}) error

XML unmarshals the response body into the provided value. The body is read and cached on the first call.

Example:

type User struct {
	ID   int    `xml:"id"`
	Name string `xml:"name"`
}

type RetryConfig

type RetryConfig struct {
	// MaxRetries is the maximum number of retry attempts
	MaxRetries int

	// Backoff is the base duration between retries (multiplied by attempt number for exponential backoff)
	Backoff time.Duration

	// RetryIf is a function that determines whether a request should be retried
	// based on the response or error. If nil, defaultRetryCondition is used.
	RetryIf func(*http.Response, error) bool
}

RetryConfig configures the retry behavior for failed HTTP requests. It defines the maximum number of retries, backoff duration, and a custom condition function to determine if a request should be retried.

func DefaultRetryConfig

func DefaultRetryConfig() *RetryConfig

DefaultRetryConfig returns a RetryConfig with sensible defaults: - 3 maximum retries - 1 second base backoff - Retries on network errors, 5xx status codes, and 429 (rate limit)

Example:

config := httpc.DefaultRetryConfig()
// Customize if needed
config.MaxRetries = 5

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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