http

package
v1.2.4 Latest Latest
Warning

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

Go to latest
Published: Jan 1, 2026 License: Apache-2.0 Imports: 4 Imported by: 3

README

HTTP

Simplified HTTP client and server utilities for Go.

Overview

The http package provides convenient wrapper functions around Go's standard net/http and gorilla/mux packages. It simplifies making HTTP requests and managing HTTP servers with powerful routing capabilities while reducing boilerplate code.

Features

  • HTTP Client - Simplified request function with built-in authentication
  • HTTP Server - Easy server setup with gorilla/mux routing
  • Handler Registration - Multiple registration methods for different use cases
  • Path Prefix Routing - Route groups and static file serving
  • Middleware Support - Chain middleware functions
  • Graceful Shutdown - Proper server lifecycle management
  • Custom Transport - Configure HTTP client transport settings

Installation

go get -u github.com/common-library/go/http
go get -u github.com/gorilla/mux

Quick Start

HTTP Client
import "github.com/common-library/go/http"

func main() {
    resp, err := http.Request(
        "https://api.example.com/users",
        http.MethodGet,
        nil,  // headers
        "",   // body
        10,   // timeout in seconds
        "",   // username
        "",   // password
        nil,  // transport
    )
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Status: %d\n", resp.StatusCode)
    fmt.Printf("Body: %s\n", resp.Body)
}
HTTP Server
import (
    "net/http"
    "github.com/common-library/go/http"
)

func main() {
    var server http.Server
    
    // Register handlers
    server.RegisterHandlerFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })
    
    server.RegisterHandlerFunc("/api/users", usersHandler, http.MethodGet)
    
    // Start server
    err := server.Start(":8080", func(err error) {
        log.Fatal(err)
    })
    if err != nil {
        log.Fatal(err)
    }
    
    // Keep running
    select {}
}

HTTP Client

Request Function
func Request(
    url string,
    method string,
    header map[string][]string,
    body string,
    timeout time.Duration,
    username string,
    password string,
    transport *http.Transport,
) (Response, error)

Performs an HTTP request and returns the complete response.

Parameters:

  • url - Target URL
  • method - HTTP method (http.MethodGet, http.MethodPost, etc.)
  • header - HTTP headers as map[string][]string
  • body - Request body as string
  • timeout - Request timeout duration (e.g., 10*time.Second)
  • username - Username for Basic Auth (empty for no auth)
  • password - Password for Basic Auth (empty for no auth)
  • transport - Custom HTTP transport (nil for default)

Returns:

  • Response - Response struct with Header, Body, and StatusCode
  • error - Error if request fails
Response Type
type Response struct {
    Header     http.Header
    Body       string
    StatusCode int
}
Client Examples
Simple GET Request
resp, err := http.Request(
    "https://api.example.com/users",
    http.MethodGet,
    nil,
    "",
    10*time.Second,
    "", "",
    nil,
)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Status: %d\n", resp.StatusCode)
fmt.Printf("Body: %s\n", resp.Body)
POST Request with JSON
headers := map[string][]string{
    "Content-Type": {"application/json"},
}

body := `{
    "name": "Alice",
    "email": "alice@example.com"
}`

resp, err := http.Request(
    "https://api.example.com/users",
    http.MethodPost,
    headers,
    body,
    30*time.Second,
    "", "",
    nil,
)

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

fmt.Printf("Created user, status: %d\n", resp.StatusCode)
Request with Authentication
resp, err := http.Request(
    "https://api.example.com/admin/stats",
    http.MethodGet,
    nil,
    "",
    10*time.Second,
    "admin",      // username
    "password123", // password
    nil,
)

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

if resp.StatusCode == 401 {
    log.Println("Authentication failed")
} else {
    fmt.Println(resp.Body)
}
Request with Custom Headers
headers := map[string][]string{
    "Authorization": {"Bearer token123"},
    "X-API-Key":     {"secret456"},
    "Accept":        {"application/json"},
}

resp, err := http.Request(
    "https://api.example.com/data",
    http.MethodGet,
    headers,
    "",
    15*time.Second,
    "", "",
    nil,
)
Request with Custom Transport
import "crypto/tls"

// Skip TLS verification (not recommended for production)
transport := &http.Transport{
    TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}

resp, err := http.Request(
    "https://self-signed.example.com/api",
    http.MethodGet,
    nil,
    "",
    10*time.Second,
    "", "",
    transport,
)

HTTP Server

Server Type
type Server struct {
    // Contains unexported fields
}
Handler Registration Methods
RegisterHandler
func (s *Server) RegisterHandler(path string, handler http.Handler, methods ...string)

Registers an HTTP handler for a specific path.

Example:

type MyHandler struct{}

func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello from handler"))
}

var server http.Server

// All methods
server.RegisterHandler("/api", &MyHandler{})

// GET only
server.RegisterHandler("/users", &MyHandler{}, http.MethodGet)

// GET and POST
server.RegisterHandler("/items", &MyHandler{}, http.MethodGet, http.MethodPost)
RegisterHandlerFunc
func (s *Server) RegisterHandlerFunc(path string, handlerFunc http.HandlerFunc, methods ...string)

Registers an HTTP handler function for a specific path.

Example:

var server http.Server

// All methods
server.RegisterHandlerFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("pong"))
})

// GET only
server.RegisterHandlerFunc("/users", func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.Write([]byte(`[{"id": 1, "name": "Alice"}]`))
}, http.MethodGet)

// POST only
server.RegisterHandlerFunc("/users", func(w http.ResponseWriter, r *http.Request) {
    // Create user
    w.WriteHeader(http.StatusCreated)
}, http.MethodPost)
RegisterPathPrefixHandler
func (s *Server) RegisterPathPrefixHandler(prefix string, handler http.Handler, methods ...string)

Registers a handler for all paths matching the prefix.

Example:

// Serve static files
fileServer := http.FileServer(http.Dir("./static"))
server.RegisterPathPrefixHandler("/static/", http.StripPrefix("/static/", fileServer))

// API v1 endpoints
server.RegisterPathPrefixHandler("/api/v1/", apiV1Handler, http.MethodGet)
RegisterPathPrefixHandlerFunc
func (s *Server) RegisterPathPrefixHandlerFunc(prefix string, handlerFunc http.HandlerFunc, methods ...string)

Registers a handler function for paths matching the prefix.

Example:

server.RegisterPathPrefixHandlerFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.Write([]byte(`{"status": "ok"}`))
})
Server Lifecycle
Start
func (s *Server) Start(address string, listenAndServeFailureFunc func(err error)) error

Starts the HTTP server.

Example:

var server http.Server

// Simple start
err := server.Start(":8080", func(err error) {
    log.Fatal(err)
})
Use
func (s *Server) Use(middleware ...mux.MiddlewareFunc)

Registers global middleware.

Example:

var server http.Server

loggingMiddleware := func(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Printf("%s %s", r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
    })
}

server.Use(loggingMiddleware)
server.Start(":8080", nil)
Stop
func (s *Server) Stop(shutdownTimeout time.Duration) error

Gracefully shuts down the server.

Example:

// Shutdown with 30 second timeout
err := server.Stop(30 * time.Second)
if err != nil {
    log.Printf("Shutdown error: %v", err)
}
IsRunning
func (s *Server) IsRunning() bool

Returns whether the server is currently running.

Example:

if server.IsRunning() {
    log.Println("Server is running")
}
GetRouter
func (s *Server) GetRouter() *mux.Router

Returns the gorilla/mux router instance for advanced configuration.

Example:

router := server.GetRouter()
router.StrictSlash(true)
router.HandleFunc("/", homeHandler)
SetRouter
func (s *Server) SetRouter(router *mux.Router)

Sets a custom router.

Example:

router := mux.NewRouter()
router.StrictSlash(true)
router.HandleFunc("/", homeHandler)

var server http.Server
server.SetRouter(router)
server.Start(":8080", nil)

Complete Examples

REST API Server
package main

import (
    "encoding/json"
    "log"
    "net/http"
    
    httplib "github.com/common-library/go/http"
)

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

var users = []User{
    {ID: 1, Name: "Alice"},
    {ID: 2, Name: "Bob"},
}

func main() {
    var server httplib.Server
    
    // GET /api/users - List all users
    server.RegisterHandlerFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(users)
    }, http.MethodGet)
    
    // POST /api/users - Create user
    server.RegisterHandlerFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
        var user User
        if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
        
        user.ID = len(users) + 1
        users = append(users, user)
        
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusCreated)
        json.NewEncoder(w).Encode(user)
    }, http.MethodPost)
    
    log.Println("Server starting on :8080")
    server.Start(":8080", func(err error) {
        log.Fatal(err)
    })
    
    select {}
}
Static File Server
package main

import (
    "log"
    "net/http"
    
    httplib "github.com/common-library/go/http"
)

func main() {
    var server httplib.Server
    
    // Serve static files from ./public directory
    fileServer := http.FileServer(http.Dir("./public"))
    server.RegisterPathPrefixHandler("/", fileServer)
    
    log.Println("Static file server on :8080")
    server.Start(":8080", nil)
    
    select {}
}
Server with Middleware
package main

import (
    "log"
    "net/http"
    "time"
    
    "github.com/gorilla/mux"
    httplib "github.com/common-library/go/http"
)

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        log.Printf("Started %s %s", r.Method, r.URL.Path)
        
        next.ServeHTTP(w, r)
        
        log.Printf("Completed in %v", time.Since(start))
    })
}

func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        apiKey := r.Header.Get("X-API-Key")
        if apiKey != "secret123" {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        
        next.ServeHTTP(w, r)
    })
}

func main() {
    var server httplib.Server
    
    server.RegisterHandlerFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Authenticated data"))
    })
    
    server.Use(loggingMiddleware)
    server.Use(authMiddleware)
    server.Start(":8080", nil)
    
    select {}
}
Server with Graceful Shutdown
package main

import (
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    
    httplib "github.com/common-library/go/http"
)

func main() {
    var server httplib.Server
    
    server.RegisterHandlerFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })
    
    // Start server
    log.Println("Starting server on :8080")
    server.Start(":8080", func(err error) {
        log.Printf("Server error: %v", err)
    })
    
    // Wait for interrupt signal
    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
    <-sigChan
    
    log.Println("Shutting down server...")
    if err := server.Stop(30 * time.Second); err != nil {
        log.Printf("Shutdown error: %v", err)
    }
    
    log.Println("Server stopped gracefully")
}
API Client Wrapper
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    
    httplib "github.com/common-library/go/http"
)

type APIClient struct {
    baseURL string
    apiKey  string
}

func NewAPIClient(baseURL, apiKey string) *APIClient {
    return &APIClient{
        baseURL: baseURL,
        apiKey:  apiKey,
    }
}

func (c *APIClient) GetUsers() ([]User, error) {
    headers := map[string][]string{
        "Authorization": {fmt.Sprintf("Bearer %s", c.apiKey)},
        "Accept":        {"application/json"},
    }
    
    resp, err := httplib.Request(
        c.baseURL+"/api/users",
        http.MethodGet,
        headers,
        "",
        30*time.Second,
        "", "",
        nil,
    )
    if err != nil {
        return nil, err
    }
    
    if resp.StatusCode != 200 {
        return nil, fmt.Errorf("API error: %d", resp.StatusCode)
    }
    
    var users []User
    if err := json.Unmarshal([]byte(resp.Body), &users); err != nil {
        return nil, err
    }
    
    return users, nil
}

func (c *APIClient) CreateUser(user User) error {
    headers := map[string][]string{
        "Authorization": {fmt.Sprintf("Bearer %s", c.apiKey)},
        "Content-Type":  {"application/json"},
    }
    
    body, _ := json.Marshal(user)
    
    resp, err := httplib.Request(
        c.baseURL+"/api/users",
        http.MethodPost,
        headers,
        string(body),
        30*time.Second,
        "", "",
        nil,
    )
    if err != nil {
        return err
    }
    
    if resp.StatusCode != 201 {
        return fmt.Errorf("API error: %d - %s", resp.StatusCode, resp.Body)
    }
    
    return nil
}

func main() {
    client := NewAPIClient("https://api.example.com", "secret123")
    
    users, err := client.GetUsers()
    if err != nil {
        log.Fatal(err)
    }
    
    for _, user := range users {
        fmt.Printf("User: %+v\n", user)
    }
}

Best Practices

1. Always Set Timeouts
// Good: Set reasonable timeout
resp, err := http.Request(url, http.MethodGet, nil, "", 30*time.Second, "", "", nil)

// Avoid: Very long or no timeout
// May hang indefinitely
2. Handle Response Status Codes
// Good: Check status code
resp, err := http.Request(url, http.MethodGet, nil, "", 10, "", "", nil)
if err != nil {
    log.Fatal(err)
}

switch resp.StatusCode {
case 200:
    fmt.Println("Success:", resp.Body)
case 404:
    fmt.Println("Not found")
case 500:
    fmt.Println("Server error")
default:
    fmt.Printf("Unexpected status: %d\n", resp.StatusCode)
}

// Avoid: Ignoring status code
// resp, _ := http.Request(...)
// fmt.Println(resp.Body) // May not be what you expect
3. Use Proper HTTP Methods
// Good: Use correct method constants
http.Request(url, http.MethodGet, ...)
http.Request(url, http.MethodPost, ...)
http.Request(url, http.MethodPut, ...)

// Avoid: String literals
// http.Request(url, "GET", ...)
4. Set Content-Type Headers
// Good: Set Content-Type for POST/PUT
headers := map[string][]string{
    "Content-Type": {"application/json"},
}

resp, _ := http.Request(url, http.MethodPost, headers, jsonBody, 10*time.Second, "", "", nil)

// Avoid: Missing Content-Type
// Server may not parse body correctly
5. Implement Graceful Shutdown
// Good: Graceful shutdown
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
<-sigChan

server.Stop(30) // Wait for active connections

// Avoid: Abrupt termination
// os.Exit(0) // May interrupt active requests
6. Use Middleware for Cross-Cutting Concerns
// Good: Centralize logging, auth, CORS in middleware
server.Use(loggingMiddleware)
server.Use(authMiddleware)
server.Use(corsMiddleware)
server.Start(":8080", nil)

// Avoid: Repeating logic in every handler
// Each handler implements its own logging

Error Handling

Client Errors
resp, err := http.Request(url, http.MethodGet, nil, "", 10, "", "", nil)
if err != nil {
    // Network error, timeout, DNS failure, etc.
    log.Printf("Request failed: %v", err)
    return
}

// Check HTTP status
if resp.StatusCode >= 400 {
    log.Printf("HTTP error: %d - %s", resp.StatusCode, resp.Body)
}
Server Errors
server.RegisterHandlerFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
    data, err := fetchData()
    if err != nil {
        http.Error(w, "Internal server error", http.StatusInternalServerError)
        log.Printf("Error fetching data: %v", err)
        return
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(data)
})

Performance Tips

  1. Connection Reuse - HTTP client reuses connections automatically
  2. Timeouts - Set appropriate timeouts to prevent hanging requests
  3. Custom Transport - Use transport for connection pooling configuration
  4. Middleware Ordering - Order middleware from general to specific
  5. Graceful Shutdown - Allow active requests to complete

Testing

Unit Testing HTTP Handlers
func TestUserHandler(t *testing.T) {
    req := httptest.NewRequest(http.MethodGet, "/api/users", nil)
    rec := httptest.NewRecorder()
    
    userHandler(rec, req)
    
    if rec.Code != http.StatusOK {
        t.Errorf("Expected status 200, got %d", rec.Code)
    }
}
Integration Testing
func TestServer(t *testing.T) {
    var server httplib.Server
    
    server.RegisterHandlerFunc("/test", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("test response"))
    })
    
    server.Start(":8081", nil)
    defer server.Stop(5)
    
    time.Sleep(100 * time.Millisecond) // Wait for server
    
    resp, err := httplib.Request(
        "http://localhost:8081/test",
        http.MethodGet,
        nil, "", 5, "", "", nil,
    )
    
    if err != nil {
        t.Fatal(err)
    }
    
    if resp.StatusCode != 200 {
        t.Errorf("Expected 200, got %d", resp.StatusCode)
    }
    
    if resp.Body != "test response" {
        t.Errorf("Unexpected body: %s", resp.Body)
    }
}

Dependencies

  • net/http - Go standard library
  • github.com/gorilla/mux - HTTP router and dispatcher

Further Reading

Documentation

Overview

Package http provides simplified HTTP client and server utilities.

This package wraps Go's standard net/http and gorilla/mux packages, offering convenient functions for making HTTP requests and managing HTTP servers with routing capabilities.

Features:

  • Simplified HTTP client with authentication support
  • HTTP server with routing (powered by gorilla/mux)
  • Handler and middleware registration
  • Path prefix routing
  • Graceful server shutdown
  • Custom transport configuration

Example:

// Client
resp, _ := http.Request("http://api.example.com", http.MethodGet, nil, "", 10, "", "", nil)

// Server
var server http.Server
server.RegisterHandlerFunc("/api", handler)
server.Start(":8080", nil)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Response

type Response struct {
	Header     net_http.Header
	Body       string
	StatusCode int
}

Response is response information.

func Request

func Request(url, method string, header map[string][]string, body string, timeout time.Duration, username, password string, transport *net_http.Transport) (Response, error)

Request performs an HTTP request and returns the response.

Parameters:

  • url: Target URL for the HTTP request
  • method: HTTP method (http.MethodGet, http.MethodPost, etc.)
  • header: HTTP headers as a map of header names to value slices
  • body: Request body as a string
  • timeout: Request timeout duration (e.g., 10*time.Second)
  • username: Username for HTTP Basic Authentication (empty string for no auth)
  • password: Password for HTTP Basic Authentication (empty string for no auth)
  • transport: Custom HTTP transport configuration (nil for default)

Returns:

  • Response: HTTP response containing headers, body, and status code
  • error: Error if request fails, nil on success

The function creates an HTTP client with the specified timeout and transport settings, performs the request, and returns the complete response. The response body is read entirely into memory.

Example:

// Simple GET request
resp, err := http.Request(
    "https://api.example.com/users",
    http.MethodGet,
    nil,              // no headers
    "",               // no body
    10*time.Second,   // 10 second timeout
    "",               // no username
    "",               // no password
    nil,              // default transport
)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Status: %d\n", resp.StatusCode)
fmt.Printf("Body: %s\n", resp.Body)

// POST request with headers and authentication
headers := map[string][]string{
    "Content-Type": {"application/json"},
    "X-API-Key":    {"secret123"},
}
body := `{"name": "Alice", "email": "alice@example.com"}`
resp, err = http.Request(
    "https://api.example.com/users",
    http.MethodPost,
    headers,
    body,
    30*time.Second,
    "admin",
    "password123",
    nil,
)

Directories

Path Synopsis
Package echo provides a simplified wrapper around the Echo web framework.
Package echo provides a simplified wrapper around the Echo web framework.
Package gin provides a simplified wrapper around the Gin web framework.
Package gin provides a simplified wrapper around the Gin web framework.
Package http provides simplified HTTP client and server utilities.
Package http provides simplified HTTP client and server utilities.

Jump to

Keyboard shortcuts

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