httpx

package module
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: May 8, 2026 License: MIT Imports: 14 Imported by: 0

README

httpx

Build Status codecov Go Report Card
GoDoc

Simple, composable HTTP client with middleware for Go.

Features

  • Option-based client configuration (timeout, transport, middlewares)
  • Composable, chainable middlewares (logging, debugging, tracing, mocking)
  • Pluggable transport layer (custom TLS, connection tuning)
  • Friendly for unit tests via an HTTP mock middleware

Installation

go get github.com/goapt/httpx

Quick Start

package main

import (
	"net/http"
	"time"

	"github.com/goapt/httpx"
)

func main() {
	client := httpx.NewClient(
		httpx.WithTimeout(5*time.Second),
		httpx.WithMiddleware(httpx.Debug()),
	)

	req, _ := http.NewRequest(http.MethodGet, "https://httpbin.org/get", nil)
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()
}

Middlewares

The middleware model wraps a http.RoundTripper in a chain, allowing cross-cutting features without coupling to request logic.

  • AccessLog: structured access logging
  • Debug: human-readable request/response dump for local development
  • Trace: OpenTelemetry tracing for HTTP client requests
  • Mock: programmable mock responses for tests
AccessLog
import (
	"bytes"
	"net/http"

	"github.com/goapt/httpx"
	"github.com/goapt/logger"
)

func exampleAccessLog() {
	l := logger.New(&logger.Config{Mode: logger.ModeStd})
	client := httpx.NewClient(httpx.WithMiddleware(httpx.AccessLog(l)))

	req, _ := http.NewRequest(http.MethodPost, "https://httpbin.org/anything", bytes.NewReader([]byte(`{"k":"v"}`)))
	req.Header.Set("Content-Type", "application/json; charset=utf-8")
	resp, _ := client.Do(req)
	defer resp.Body.Close()
}
Debug
client := httpx.NewClient(httpx.WithMiddleware(httpx.Debug()))
resp, _ := client.Get("https://httpbin.org/json")
defer resp.Body.Close()
Trace (OpenTelemetry)
client := httpx.NewClient(httpx.WithMiddleware(httpx.Trace()))
resp, _ := client.Get("https://httpbin.org/get")
defer resp.Body.Close()
HTTP Mock (for tests)
import (
	"bytes"
	"errors"

	"github.com/goapt/httpx"
)

func exampleMock() {
	suites := []httpx.MockSuite{
		{URI: "/get", ResponseBody: "ok"},
		{URI: "/user/id/.*", ResponseBody: "user"},
		{URI: "/find\\?id=.*", ResponseBody: "find"},
		{URI: "/bodymatch", MatchBody: map[string]any{"user_id": 1}, ResponseBody: "body-ok"},
		{URI: "/query", MatchQuery: map[string]any{"name": "test"}, ResponseBody: "query-ok"},
		{URI: "/error", Error: errors.New("mock error")},
	}

	client := httpx.NewClient(httpx.WithMiddleware(httpx.Mock(suites)))
	body := bytes.NewBufferString(`{"user_id":1}`)
	resp, _ := client.Post("/bodymatch", "application/json; charset=utf-8", body)
	defer resp.Body.Close()
}

Custom Middleware

import (
	"net/http"

	"github.com/goapt/httpx"
)

func exampleCustomMW() {
	logMW := func(next http.RoundTripper) http.RoundTripper {
		return httpx.RoundTripFunc(func(req *http.Request) (*http.Response, error) {
			resp, err := next.RoundTrip(req)
			return resp, err
		})
	}

	client := httpx.NewClient(httpx.WithMiddleware(logMW))
	_ = client
}

Custom Transport

import (
	"crypto/tls"
	"net/http"

	"github.com/goapt/httpx"
)

func exampleTransport() {
	tr := http.DefaultTransport.(*http.Transport).Clone()
	tr.TLSClientConfig = &tls.Config{
		CipherSuites: []uint16{tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384},
	}

	client := httpx.NewClient(httpx.WithTransport(tr))
	resp, _ := client.Get("https://httpbin.org/json")
	defer resp.Body.Close()
}

Documentation

Overview

Example (Chain)
package main

import (
	"fmt"
	"net/http"
)

func mid1() Middleware {
	return func(tr http.RoundTripper) http.RoundTripper {
		return RoundTripFunc(func(req *http.Request) (resp *http.Response, err error) {
			fmt.Println(1)
			defer func() {
				fmt.Println("mid1 defer")
			}()
			return tr.RoundTrip(req)
		})
	}
}

func mid2() Middleware {
	return func(tr http.RoundTripper) http.RoundTripper {
		return RoundTripFunc(func(req *http.Request) (resp *http.Response, err error) {
			fmt.Println(2)
			defer func() {
				fmt.Println("mid2 defer")
			}()
			return tr.RoundTrip(req)
		})
	}
}

func tr() http.RoundTripper {
	return RoundTripFunc(func(req *http.Request) (resp *http.Response, err error) {
		fmt.Println("tr")
		w := &http.Response{
			StatusCode: 200,
		}

		return w, nil
	})
}

func main() {
	tr := chain(tr(), []Middleware{mid1(), mid2()}...)

	client := http.Client{
		Transport: tr,
	}

	req, _ := http.NewRequest(http.MethodGet, "https://demo.com/test", nil)

	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		panic("status code error")
	}

}
Output:
1
2
tr
mid2 defer
mid1 defer

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewClient

func NewClient(options ...Option) *http.Client

Types

type Client

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

type Middleware

type Middleware func(http.RoundTripper) http.RoundTripper

Middleware is HTTP Client transport middleware.

func AccessLog

func AccessLog(logger *slog.Logger) Middleware

func Debug

func Debug() Middleware

func Mock

func Mock(suite []MockSuite) Middleware

Mock quickly define HTTP Response for mock RoundTriper

func Trace

func Trace() Middleware

type MockSuite

type MockSuite struct {
	URI                 string
	MatchBody           map[string]any
	MatchQuery          map[string]any
	ResponseBody        string
	StatusCode          int
	Header              http.Header
	Error               error
	ResponseInterceptor func(response *http.Response, body []byte) *http.Response
}

MockSuite is test set for http client

type Option

type Option func(c *Client)

func WithMiddleware

func WithMiddleware(middleware ...Middleware) Option

func WithTimeout

func WithTimeout(t time.Duration) Option

func WithTransport

func WithTransport(transport http.RoundTripper) Option

type RoundTripFunc

type RoundTripFunc func(*http.Request) (*http.Response, error)

RoundTripFunc is a holder function to make the process of creating middleware a bit easier without requiring the consumer to implement the RoundTripper interface.

func (RoundTripFunc) RoundTrip

func (rt RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error)

Jump to

Keyboard shortcuts

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