httpclient

package module
v1.6.1 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2025 License: MIT Imports: 5 Imported by: 1

README

http-client

Universal HTTP client for Go with fluent API, streaming support, and zero third-party dependencies.

Features

  • Fluent API - method chaining for building requests
  • Streaming - efficient memory usage with io.Pipe for large payloads
  • Context-aware - respects context cancellation to prevent goroutine leaks
  • Multipart/form-data - file uploads with streaming support
  • Type-safe - typed methods for query parameters (Bool, Int, Float)
  • Zero dependencies - only Go standard library

Installation

go get github.com/nativebpm/http-client

Quick Start

package main

import (
    "context"
    "log"
    "net/http"
    "github.com/nativebpm/http-client"
)

func main() {
    client, err := httpclient.NewClient(&http.Client{}, "https://api.example.com")
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    // Simple GET request
    resp, err := client.GET(ctx, "/users").Send()
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    // POST with JSON body
    user := map[string]string{"name": "John", "email": "john@example.com"}
    resp, err = client.POST(ctx, "/users").
        Header("Authorization", "Bearer token").
        JSON(user).
        Send()
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
}

Usage Examples

Standard Requests
ctx := context.Background()

// GET with query parameters
resp, err := client.GET(ctx, "/users").
    Param("page", "1").
    Int("limit", 10).
    Bool("active", true).
    Send()

// PUT with JSON
resp, err := client.PUT(ctx, "/users/123").
    Header("Content-Type", "application/json").
    JSON(updatedUser).
    Send()

// DELETE
resp, err := client.DELETE(ctx, "/users/123").Send()

// Custom method
resp, err := client.Request(ctx, "PATCH", "/users/123").
    JSON(partialUpdate).
    Send()
Multipart File Uploads
file, _ := os.Open("document.pdf")
defer file.Close()

// POST with file (default)
resp, err := client.Multipart(ctx, "/upload").
    Param("description", "Important document").
    File("document", "document.pdf", file).
    Send()

// PUT with custom method
resp, err := client.MultipartWithMethod(ctx, "/upload", http.MethodPut).
    Param("title", "Updated File").
    Int("version", 2).
    File("document", "document.pdf", file).
    Send()
Multiple Files
resp, err := client.Multipart(ctx, "/upload").
    Param("folder", "documents").
    File("file1", "doc1.pdf", reader1).
    File("file2", "doc2.pdf", reader2).
    File("file3", "image.png", reader3).
    Send()
Request with Timeout
ctx := context.Background()

// Using Timeout() method (recommended)
resp, err := client.POST(ctx, "/long-operation").
    Timeout(30 * time.Second).
    JSON(data).
    Send()

// Or using context.WithTimeout
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
resp, err = client.POST(ctx, "/long-operation").
    JSON(data).
    Send()

// Timeout with multipart upload
resp, err = client.Multipart(ctx, "/upload").
    Timeout(60 * time.Second).
    File("document", "large.pdf", file).
    Send()

API Reference

Client
// Create new client
NewClient(httpClient *http.Client, baseURL string) (*Client, error)

// Standard HTTP methods (convenience)
GET(ctx context.Context, path string) *Request
POST(ctx context.Context, path string) *Request
PUT(ctx context.Context, path string) *Request
PATCH(ctx context.Context, path string) *Request
DELETE(ctx context.Context, path string) *Request

// Generic request builder
Request(ctx context.Context, method, path string) *Request

// Multipart requests
Multipart(ctx context.Context, path string) *Multipart  // POST by default
MultipartWithMethod(ctx context.Context, path, method string) *Multipart
Request Builder
// Headers
Header(key, value string) *Request

// Query parameters
Param(key, value string) *Request
Bool(key string, value bool) *Request
Int(key string, value int) *Request
Float(key string, value float64) *Request

// Body
Body(body io.ReadCloser, contentType string) *Request
JSON(data any) *Request  // Streams JSON with context cancellation

// Timeout
Timeout(duration time.Duration) *Request

// Execute
Send() (*http.Response, error)
Multipart Builder
// Headers
Header(key, value string) *Multipart

// Form fields
Param(key, value string) *Multipart
Bool(key string, value bool) *Multipart
Int(key string, value int) *Multipart
Float(key string, value float64) *Multipart

// Files
File(key, filename string, content io.Reader) *Multipart

// Timeout
Timeout(duration time.Duration) *Multipart

// Execute
Send() (*http.Response, error)  // Streams data with context cancellation

Key Features Explained

Streaming Support

Both JSON and multipart requests use io.Pipe for efficient streaming:

  • Low memory usage - data is streamed, not buffered entirely in memory
  • Large file support - upload gigabyte-sized files without OOM
  • Automatic encoding - JSON is encoded on-the-fly during transmission
Context Cancellation

All operations respect context cancellation:

  • No goroutine leaks - background goroutines exit cleanly when context is cancelled
  • Timeout support - use context.WithTimeout for automatic timeouts
  • Graceful shutdown - cancel ongoing requests during application shutdown
Type Safety

Typed parameter methods prevent common mistakes:

client.GET(ctx, "/api").
    Int("page", 1).      // Not Param("page", "1")
    Bool("active", true). // Not Param("active", "true")
    Float("price", 99.99). // Not Param("price", "99.99")
    Timeout(5 * time.Second). // Type-safe timeout
    Send()

Testing

Run all tests:

go test -v ./...

Run with benchmarks:

go test -v -bench=. ./...

Run specific tests:

go test -v -run TestMultipart ./request

Project Structure

http-client/
├── httpclient.go              # Main client with convenience methods
├── httpclient_test.go         # Client tests
├── request/
│   ├── constants.go           # HTTP constants and types
│   ├── request.go             # Standard request builder
│   ├── multipart.go           # Multipart/form-data builder
│   ├── request_test.go        # Request tests
│   ├── multipart_test.go      # Multipart tests
│   ├── request_bench_test.go  # Request benchmarks
│   └── multipart_bench_test.go # Multipart benchmarks
├── go.mod
└── README.md

Performance

The library is designed for efficiency:

  • Zero allocations for method chaining (returns pointer)
  • Streaming I/O reduces memory pressure
  • Minimal overhead - thin wrapper around net/http

Benchmark results on typical hardware:

BenchmarkClientMethods-8        1000000    1234 ns/op    456 B/op    12 allocs/op
BenchmarkMultipart-8             500000    2345 ns/op    789 B/op    15 allocs/op

Best Practices

  1. Always use context - pass context.Background() or timeout context
  2. Defer response body close - defer resp.Body.Close() to avoid leaks
  3. Check errors - handle errors from Send() appropriately
  4. Set timeouts - use Timeout() method or context.WithTimeout for long-running operations
  5. Reuse http.Client - create one http.Client and reuse it

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

License

MIT — see LICENSE

Documentation

Overview

Package httpclient provides a convenient HTTP client with request builders.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

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

Client wraps http.Client and provides request builders for different HTTP methods.

func NewClient

func NewClient(client *http.Client, baseURL string) (*Client, error)

NewClient creates a new HTTP client with the given base URL. Returns an error if the base URL is invalid.

func (*Client) DELETE added in v1.6.0

func (c *Client) DELETE(ctx context.Context, path string) *request.Request

DELETE creates a DELETE request builder.

func (*Client) GET added in v1.6.0

func (c *Client) GET(ctx context.Context, path string) *request.Request

GET creates a GET request builder.

func (*Client) Multipart added in v1.6.0

func (c *Client) Multipart(ctx context.Context, path string) *request.Multipart

Multipart creates a multipart/form-data POST request builder.

func (*Client) MultipartWithMethod added in v1.6.0

func (c *Client) MultipartWithMethod(ctx context.Context, path, method string) *request.Multipart

MultipartWithMethod creates a multipart/form-data request builder with HTTP method.

func (*Client) PATCH added in v1.6.0

func (c *Client) PATCH(ctx context.Context, path string) *request.Request

PATCH creates a PATCH request builder.

func (*Client) POST added in v1.6.0

func (c *Client) POST(ctx context.Context, path string) *request.Request

POST creates a POST request builder.

func (*Client) PUT added in v1.6.0

func (c *Client) PUT(ctx context.Context, path string) *request.Request

PUT creates a PUT request builder.

func (*Client) Request added in v1.6.0

func (c *Client) Request(ctx context.Context, method, path string) *request.Request

Request creates a standard HTTP request builder.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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