gohttpx

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 1, 2025 License: MIT Imports: 12 Imported by: 0

README

go-httpx

Go Report Card Go Version License

A lightweight and expressive HTTP client library for Go, inspired by Axios. go-httpx provides a simple and powerful API for making HTTP requests with features like automatic JSON handling, interceptors, and comprehensive configuration options.

Features

  • 🚀 Simple API: Easy-to-use methods similar to Axios
  • 📦 Auto JSON: Automatic JSON serialization/deserialization
  • 🔧 Flexible Configuration: Base URL, headers, timeouts, and more
  • 🔄 Interceptors: Request and response interceptors for middleware functionality
  • Performance: Keep-alive connections and connection pooling
  • 🛡️ Error Handling: Comprehensive error handling with detailed error information
  • 🔒 Type Safety: Full Go type safety and IDE support

Installation

go get github.com/vanduc0209/go-httpx

Quick Start

Basic Usage
package main

import (
    "fmt"
    "log"
    "github.com/vanduc0209/go-httpx"
)

func main() {
    // Simple GET request
    resp, err := httpx.Get("https://jsonplaceholder.typicode.com/posts/1")
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Status: %d\n", resp.Status)
    fmt.Printf("Data: %+v\n", resp.Data)
}
Creating a Client Instance
import (
    "time"
    "github.com/vanduc0209/go-httpx"
)

// Create a configured client
config := &httpx.Config{
    BaseURL: "https://api.example.com",
    Timeout: 30 * time.Second,
    Headers: map[string]string{
        "Authorization": "Bearer your-token",
        "Content-Type":  "application/json",
    },
    KeepAlive: true,
    MaxIdleConns: 100,
}

client := httpx.NewHttpX(config)

// Use the client
resp, err := client.Get("/users")

API Reference

HTTP Methods
GET Request
// Simple GET
resp, err := httpx.Get("https://api.example.com/users")

// GET with query parameters
resp, err := httpx.Get("https://api.example.com/users", &httpx.Request{
    Params: map[string]string{
        "page": "1",
        "limit": "10",
    },
})
POST Request
// POST with JSON data
user := map[string]interface{}{
    "name":  "John Doe",
    "email": "[email protected]",
}

resp, err := httpx.Post("https://api.example.com/users", user)

// POST with custom headers
resp, err := httpx.Post("https://api.example.com/users", user, &httpx.Request{
    Headers: map[string]string{
        "Authorization": "Bearer token",
    },
})
PUT Request
// PUT with data
updateData := map[string]interface{}{
    "name": "Jane Doe",
}

resp, err := httpx.Put("https://api.example.com/users/1", updateData)
DELETE Request
// DELETE request
resp, err := httpx.Delete("https://api.example.com/users/1")
PATCH Request
// PATCH with partial data
patchData := map[string]interface{}{
    "email": "[email protected]",
}

resp, err := httpx.Patch("https://api.example.com/users/1", patchData)
Configuration Options
Client Configuration
config := &httpx.Config{
    BaseURL:      "https://api.example.com",
    Timeout:      30 * time.Second,
    MaxRedirects: 5,
    Headers: map[string]string{
        "Authorization": "Bearer token",
        "User-Agent":   "MyApp/1.0",
    },
    KeepAlive:           true,
    MaxIdleConns:        100,
    MaxIdleConnsPerHost: 10,
    IdleConnTimeout:     90 * time.Second,
    KeepAliveTimeout:    30 * time.Second,
    DisableCompression:  false,
    TLSHandshakeTimeout: 10 * time.Second,
    ResponseHeaderTimeout: 30 * time.Second,
}

client := httpx.NewHttpX(config)
Request Configuration
resp, err := httpx.Get("https://api.example.com/users", &httpx.Request{
    Headers: map[string]string{
        "Authorization": "Bearer token",
    },
    Params: map[string]string{
        "page": "1",
        "limit": "10",
    },
    Timeout: 10 * time.Second,
})
Interceptors
Request Interceptors
client := httpx.NewHttpX(nil)

// Add request interceptor
client.interceptors.Request = append(client.interceptors.Request, func(req *httpx.Request) error {
    // Add authentication header
    if req.Headers == nil {
        req.Headers = make(map[string]string)
    }
    req.Headers["Authorization"] = "Bearer " + getToken()
    return nil
})
Response Interceptors
// Add response interceptor
client.interceptors.Response = append(client.interceptors.Response, func(resp *httpx.Response) error {
    // Log response
    fmt.Printf("Response: %d - %s\n", resp.Status, resp.StatusText)
    return nil
})
Error Handling
resp, err := httpx.Get("https://api.example.com/users")
if err != nil {
    if httpxErr, ok := err.(*httpx.Error); ok {
        fmt.Printf("Error Code: %s\n", httpxErr.Code)
        fmt.Printf("Error Message: %s\n", httpxErr.Message)
        fmt.Printf("HTTP Status: %d\n", httpxErr.Response.Status)
    } else {
        fmt.Printf("Network Error: %v\n", err)
    }
    return
}
Utility Methods
client := httpx.NewHttpX(nil)

// Set base URL
client.SetBaseURL("https://api.example.com")

// Set timeout
client.SetTimeout(30 * time.Second)

// Set default headers
client.SetDefaultHeader("Authorization", "Bearer token")
client.SetDefaultHeaders(map[string]string{
    "Content-Type": "application/json",
    "User-Agent":   "MyApp/1.0",
})

Examples

REST API Client
package main

import (
    "fmt"
    "log"
    "time"
    "github.com/vanduc0209/go-httpx"
)

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

func main() {
    // Create API client
    config := &httpx.Config{
        BaseURL: "https://jsonplaceholder.typicode.com",
        Timeout: 30 * time.Second,
        Headers: map[string]string{
            "Content-Type": "application/json",
        },
    }
    
    client := httpx.NewHttpX(config)
    
    // Get users
    resp, err := client.Get("/users")
    if err != nil {
        log.Fatal(err)
    }
    
    // Parse response
    var users []User
    if userData, ok := resp.Data.([]interface{}); ok {
        // Convert to User structs
        for _, user := range userData {
            if userMap, ok := user.(map[string]interface{}); ok {
                users = append(users, User{
                    ID:    int(userMap["id"].(float64)),
                    Name:  userMap["name"].(string),
                    Email: userMap["email"].(string),
                })
            }
        }
    }
    
    fmt.Printf("Found %d users\n", len(users))
}
File Upload
package main

import (
    "fmt"
    "log"
    "os"
    "github.com/vanduc0209/go-httpx"
)

func main() {
    // Read file
    fileData, err := os.ReadFile("example.txt")
    if err != nil {
        log.Fatal(err)
    }
    
    // Upload file
    resp, err := httpx.Post("https://httpbin.org/post", fileData, &httpx.Request{
        Headers: map[string]string{
            "Content-Type": "text/plain",
        },
    })
    
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Upload successful: %d\n", resp.Status)
}
Authentication with Interceptors
package main

import (
    "fmt"
    "github.com/vanduc0209/go-httpx"
)

func main() {
    client := httpx.NewHttpX(nil)
    
    // Add authentication interceptor
    client.interceptors.Request = append(client.interceptors.Request, func(req *httpx.Request) error {
        if req.Headers == nil {
            req.Headers = make(map[string]string)
        }
        req.Headers["Authorization"] = "Bearer " + getAuthToken()
        return nil
    })
    
    // Add logging interceptor
    client.interceptors.Response = append(client.interceptors.Response, func(resp *httpx.Response) error {
        fmt.Printf("[%s] %s - %d\n", resp.Config.Method, resp.Config.URL, resp.Status)
        return nil
    })
    
    // All requests will now include authentication and logging
    resp, err := client.Get("https://api.example.com/protected")
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    
    fmt.Printf("Response: %+v\n", resp.Data)
}

func getAuthToken() string {
    // Implement your token retrieval logic
    return "your-auth-token"
}

Configuration Reference

Config Struct
type Config struct {
    BaseURL      string            // Base URL for all requests
    Timeout      time.Duration     // Default timeout
    Headers      map[string]string // Default headers
    MaxRedirects int               // Maximum redirects to follow
    
    // Keep-Alive configuration
    KeepAlive           bool          // Enable/disable keep-alive
    MaxIdleConns        int           // Maximum idle connections
    MaxIdleConnsPerHost int           // Maximum idle connections per host
    MaxConnsPerHost     int           // Maximum connections per host
    IdleConnTimeout     time.Duration // Idle connection timeout
    KeepAliveTimeout    time.Duration // Keep-alive timeout
    
    // Additional transport settings
    DisableCompression    bool          // Disable gzip compression
    TLSHandshakeTimeout   time.Duration // TLS handshake timeout
    ResponseHeaderTimeout time.Duration // Response header timeout
}
Request Struct
type Request struct {
    Method  string            // HTTP method
    URL     string            // Request URL
    Headers map[string]string // Request headers
    Data    interface{}       // Request body data
    Params  map[string]string // Query parameters
    Timeout time.Duration     // Request timeout
}
Response Struct
type Response struct {
    Data       interface{}       // Response data (parsed JSON or string)
    Status     int               // HTTP status code
    StatusText string            // HTTP status text
    Headers    map[string]string // Response headers
    Config     *Request          // Original request config
}

Error Types

The library provides detailed error information through the Error struct:

type Error struct {
    Message  string        // Error message
    Code     string        // Error code
    Config   *Request      // Request configuration
    Request  *http.Request // Original HTTP request
    Response *Response     // Response (if available)
}

Common error codes:

  • JSON_MARSHAL_ERROR: Failed to serialize request data
  • REQUEST_CREATION_ERROR: Failed to create HTTP request
  • NETWORK_ERROR: Network/connection error
  • RESPONSE_READ_ERROR: Failed to read response body
  • HTTP_ERROR: HTTP error (4xx, 5xx status codes)

Performance Considerations

Keep-Alive Connections
config := &httpx.Config{
    KeepAlive:           true,
    MaxIdleConns:        100,
    MaxIdleConnsPerHost: 10,
    IdleConnTimeout:     90 * time.Second,
    KeepAliveTimeout:    30 * time.Second,
}
Connection Pooling

The library automatically manages connection pooling when keep-alive is enabled. This is especially beneficial for:

  • High-frequency requests to the same host
  • API clients making multiple requests
  • Microservices communicating with each other
Timeout Configuration
config := &httpx.Config{
    Timeout:              30 * time.Second,  // Client timeout
    TLSHandshakeTimeout:  10 * time.Second,  // TLS handshake timeout
    ResponseHeaderTimeout: 30 * time.Second,  // Response header timeout
}

Best Practices

1. Use Client Instances for Repeated Requests
// Good: Create a client instance
client := httpx.NewHttpX(&httpx.Config{
    BaseURL: "https://api.example.com",
    Timeout: 30 * time.Second,
})

// Use the same client for multiple requests
resp1, _ := client.Get("/users")
resp2, _ := client.Get("/posts")
2. Handle Errors Properly
resp, err := httpx.Get("https://api.example.com/users")
if err != nil {
    if httpxErr, ok := err.(*httpx.Error); ok {
        switch httpxErr.Code {
        case "HTTP_ERROR":
            // Handle HTTP errors (4xx, 5xx)
            fmt.Printf("HTTP Error: %d\n", httpxErr.Response.Status)
        case "NETWORK_ERROR":
            // Handle network errors
            fmt.Printf("Network Error: %s\n", httpxErr.Message)
        default:
            // Handle other errors
            fmt.Printf("Error: %s\n", httpxErr.Message)
        }
    }
    return
}
3. Use Interceptors for Cross-Cutting Concerns
client := httpx.NewHttpX(nil)

// Add logging interceptor
client.interceptors.Request = append(client.interceptors.Request, func(req *httpx.Request) error {
    fmt.Printf("Making request: %s %s\n", req.Method, req.URL)
    return nil
})

client.interceptors.Response = append(client.interceptors.Response, func(resp *httpx.Response) error {
    fmt.Printf("Received response: %d\n", resp.Status)
    return nil
})
4. Configure Appropriate Timeouts
config := &httpx.Config{
    Timeout:              30 * time.Second,  // Overall request timeout
    TLSHandshakeTimeout:  10 * time.Second,  // TLS timeout
    ResponseHeaderTimeout: 30 * time.Second,  // Header timeout
}

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

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

Acknowledgments

  • Inspired by Axios for JavaScript
  • Built with Go's standard net/http package
  • Designed for simplicity and performance

Documentation

Index

Constants

View Source
const (
	GET    = "GET"
	POST   = "POST"
	PUT    = "PUT"
	DELETE = "DELETE"
	PATCH  = "PATCH"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	BaseURL      string            `json:"baseURL"`
	Timeout      time.Duration     `json:"timeout"`
	Headers      map[string]string `json:"headers"`
	MaxRedirects int               `json:"maxRedirects"`

	// Keep-Alive configuration
	KeepAlive           bool          `json:"keepAlive"`           // Enable/disable keep-alive
	MaxIdleConns        int           `json:"maxIdleConns"`        // Maximum idle connections
	MaxIdleConnsPerHost int           `json:"maxIdleConnsPerHost"` // Maximum idle connections per host
	MaxConnsPerHost     int           `json:"maxConnsPerHost"`     // Maximum connections per host
	IdleConnTimeout     time.Duration `json:"idleConnTimeout"`     // Idle connection timeout
	KeepAliveTimeout    time.Duration `json:"keepAliveTimeout"`    // Keep-alive timeout

	// Additional transport settings
	DisableCompression    bool          `json:"disableCompression"`    // Disable gzip compression
	TLSHandshakeTimeout   time.Duration `json:"tlsHandshakeTimeout"`   // TLS handshake timeout
	ResponseHeaderTimeout time.Duration `json:"responseHeaderTimeout"` // Response header timeout
}

Config represents client configuration

type Error

type Error struct {
	Message  string        `json:"message"`
	Code     string        `json:"code"`
	Config   *Request      `json:"config"`
	Request  *http.Request `json:"request"`
	Response *Response     `json:"response"`
}

Error represents HTTP error

func (*Error) Error

func (e *Error) Error() string

type HttpX

type HttpX struct {
	Interceptors *Interceptors
	// contains filtered or unexported fields
}

func NewHttpX

func NewHttpX(config *Config) *HttpX

func (*HttpX) Delete

func (h *HttpX) Delete(url string, config ...*Request) (*Response, error)

func (*HttpX) Get

func (h *HttpX) Get(url string, config ...*Request) (*Response, error)

Client methods

func (*HttpX) Patch

func (h *HttpX) Patch(
	url string,
	data any,
	config ...*Request,
) (*Response, error)

func (*HttpX) Post

func (h *HttpX) Post(
	url string,
	data any,
	config ...*Request,
) (*Response, error)

func (*HttpX) Put

func (h *HttpX) Put(
	url string,
	data any,
	config ...*Request,
) (*Response, error)

func (*HttpX) Request

func (h *HttpX) Request(config *Request) (*Response, error)

Generic request method

func (*HttpX) SetBaseURL

func (h *HttpX) SetBaseURL(baseURL string)

Utility functions for common use cases

func (*HttpX) SetDefaultHeader

func (h *HttpX) SetDefaultHeader(key, value string)

func (*HttpX) SetDefaultHeaders

func (h *HttpX) SetDefaultHeaders(headers map[string]string)

func (*HttpX) SetTimeout

func (h *HttpX) SetTimeout(timeout time.Duration)

type Interceptors

type Interceptors struct {
	Request  []RequestInterceptor
	Response []ResponseInterceptor
}

Interceptors for request and response

type Request

type Request struct {
	Method  string            `json:"method"`
	URL     string            `json:"url"`
	Headers map[string]string `json:"headers"`
	Data    interface{}       `json:"data"`
	Params  map[string]string `json:"params"`
	Timeout time.Duration     `json:"timeout"`
}

Request represents HTTP request configuration

type RequestInterceptor

type RequestInterceptor func(*Request) error

type Response

type Response struct {
	Data       interface{}       `json:"data"`
	Status     int               `json:"status"`
	StatusText string            `json:"statusText"`
	Headers    map[string]string `json:"headers"`
	Config     *Request          `json:"config"`
}

Response represents HTTP response

func Delete

func Delete(url string, config ...*Request) (*Response, error)

func Get

func Get(url string, config ...*Request) (*Response, error)

HTTP method functions

func Patch

func Patch(url string, data any, config ...*Request) (*Response, error)

func Post

func Post(url string, data any, config ...*Request) (*Response, error)

func Put

func Put(url string, data any, config ...*Request) (*Response, error)

type ResponseInterceptor

type ResponseInterceptor func(*Response) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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