Skip to content

goforj/httpx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

httpx Logo

A generics-first HTTP client wrapper for Go, built on top of the amazing github.com/imroc/req/v3 library. It keeps req's power and escape hatches, while making the 90% use case feel effortless.

Go Reference License: MIT Go Test Go version Latest tag Go Report Card Tests

Why httpx

  • Typed, zero-ceremony requests with generics.
  • Opinionated defaults (timeouts, result handling, safe error mapping).
  • Built on req, with full escape hatches via Client.Req() and Client.Raw().
  • Ergonomic options for headers, query params, auth, retries, dumps, and uploads.

Install

go get github.com/goforj/httpx

Quick Start

package main

import (
	"context"
	"fmt"

	"github.com/goforj/httpx"
)

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

func main() {
	c := httpx.New()

	// Simple typed GET.
	res := httpx.Get[User](c, "https://api.example.com/users/1")
	if res.Err != nil {
		panic(res.Err)
	}
	fmt.Println(res.Body.Name)

	// Context-aware GET.
	ctx := context.Background()
	res = httpx.GetCtx[User](c, ctx, "https://api.example.com/users/2")
	if res.Err != nil {
		panic(res.Err)
	}

	// Access the underlying response when you need it.
	_ = res.Response
}

Escape Hatches (req is always available)

c := httpx.New()

// Advanced req config.
c.Req().EnableDumpEachRequest()

// Drop down to raw req calls.
resp, err := c.Raw().R().Get("https://httpbin.org/uuid")
_, _ = resp, err

Options in Practice

c := httpx.New(httpx.BaseURL("https://api.example.com"))

res := httpx.Get[User](
	c,
	"/users/{id}",
	httpx.Path("id", "42"),
	httpx.Query("include", "teams", "active", "1"),
	httpx.Header("Accept", "application/json"),
)
_ = res

Debugging and Tracing

  • HTTP_TRACE=1 enables request/response dumps for all requests.
  • httpx.Dump() enables dump for a single request.
  • httpx.DumpEachRequest() enables per-request dumps on a client.

Examples

All runnable examples are generated from doc comments and live in ./examples. They are compiled by example_compile_test.go to keep docs and code in sync.

Contributing

  • Run go run ./docs/examplegen after updating doc examples.
  • Run go run ./docs/readme/main.go to refresh the API index and test count.
  • Run go test ./....

API Index

Group Functions
Auth Auth Basic Bearer
Client Default New Raw Req
Client Options BaseURL ErrorMapper Middleware Transport
Debugging Dump DumpAll DumpEachRequest DumpEachRequestTo DumpTo DumpToFile
Download Options OutputFile
Errors Error
Request Options Before Body Form Header Headers JSON Path Paths Queries Query Timeout
Requests Delete Get Patch Post Put
Requests (Context) DeleteCtx GetCtx PatchCtx PostCtx PutCtx
Retry RetryBackoff RetryCondition RetryCount RetryFixedInterval RetryHook RetryInterval
Retry (Client) Retry
Upload Options File FileBytes FileReader Files UploadCallback UploadCallbackWithInterval UploadProgress

Auth

Auth

Auth sets the Authorization header using a scheme and token.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.Auth("Token", "abc123"))

Basic

Basic sets HTTP basic authentication headers.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.Basic("user", "pass"))

Bearer

Bearer sets the Authorization header with a bearer token.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.Bearer("token"))

Client

Default

Default returns the shared default client.

c := httpx.Default()
_ = c

New

New creates a client with opinionated defaults and optional overrides.

var buf bytes.Buffer
c := httpx.New(httpx.
	BaseURL("https://api.example.com").
	Timeout(5*time.Second).
	Header("X-Trace", "1").
	Headers(map[string]string{
		"Accept": "application/json",
	}).
	Transport(http.RoundTripper(http.DefaultTransport)).
	Middleware(func(_ *req.Client, r *req.Request) error {
		r.SetHeader("X-Middleware", "1")
		return nil
	}).
	ErrorMapper(func(resp *req.Response) error {
		return fmt.Errorf("status %d", resp.StatusCode)
	}).
	DumpAll().
	DumpEachRequest().
	DumpEachRequestTo(&buf).
	Retry(func(rc *req.Client) {
		rc.SetCommonRetryCount(2)
	}).
	RetryCount(2).
	RetryFixedInterval(200 * time.Millisecond).
	RetryBackoff(100*time.Millisecond, 2*time.Second).
	RetryInterval(func(_ *req.Response, attempt int) time.Duration {
		return time.Duration(attempt) * 100 * time.Millisecond
	}).
	RetryCondition(func(resp *req.Response, _ error) bool {
		return resp != nil && resp.StatusCode == 503
	}).
	RetryHook(func(_ *req.Response, _ error) {}),
)
_ = c

Raw

Raw returns the underlying req client for chaining raw requests.

c := httpx.New()
resp, err := c.Raw().R().Get("https://httpbin.org/uuid")
_, _ = resp, err

Req

Req returns the underlying req client for advanced usage.

c := httpx.New()
c.Req().EnableDumpEachRequest()

Client Options

BaseURL

BaseURL sets a base URL on the client.

c := httpx.New(httpx.BaseURL("https://api.example.com"))
_ = c

ErrorMapper

ErrorMapper sets a custom error mapper for non-2xx responses.

c := httpx.New(httpx.ErrorMapper(func(resp *req.Response) error {
	return fmt.Errorf("status %d", resp.StatusCode)
}))
_ = c

Middleware

Middleware adds request middleware to the client.

c := httpx.New(httpx.Middleware(func(_ *req.Client, r *req.Request) error {
	r.SetHeader("X-Trace", "1")
	return nil
}))
_ = c

Transport

Transport wraps the underlying transport with a custom RoundTripper.

c := httpx.New(httpx.Transport(http.RoundTripper(http.DefaultTransport)))
_ = c

Debugging

Dump

Dump enables req's request-level dump output.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.Dump())

DumpAll

DumpAll enables req's client-level dump output for all requests.

c := httpx.New(httpx.DumpAll())
_ = c

DumpEachRequest

DumpEachRequest enables request-level dumps for each request on the client.

c := httpx.New(httpx.DumpEachRequest())
_ = c

DumpEachRequestTo

DumpEachRequestTo enables request-level dumps for each request and writes them to the provided output.

var buf bytes.Buffer
c := httpx.New(httpx.DumpEachRequestTo(&buf))
_ = httpx.Get[string](c, "https://example.com")
_ = buf.String()

DumpTo

DumpTo enables req's request-level dump output to a writer.

var buf bytes.Buffer
c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.DumpTo(&buf))

DumpToFile

DumpToFile enables req's request-level dump output to a file path.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.DumpToFile("httpx.dump"))

Download Options

OutputFile

OutputFile streams the response body to a file path.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com/file", httpx.OutputFile("/tmp/file.bin"))

Errors

Error

Error returns a short, human-friendly summary of the HTTP error.

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

c := httpx.New()
res := httpx.Get[User](c, "https://example.com/users/1")
var httpErr *httpx.HTTPError
if errors.As(res.Err, &httpErr) {
	_ = httpErr.StatusCode
}

Request Options

Before

Before runs a hook before the request is sent.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.Before(func(r *req.Request) {
	r.EnableDump()
}))

Body

Body sets the request body and infers JSON for structs and maps.

type Payload struct {
	Name string `json:"name"`
}

c := httpx.New()
_ = httpx.Post[any, string](c, "https://example.com", nil, httpx.Body(Payload{Name: "Ana"}))

Form

Form sets form data for the request.

c := httpx.New()
_ = httpx.Post[any, string](c, "https://example.com", nil, httpx.Form(map[string]string{
	"name": "Ana",
}))

Header

Header sets a header on a request or client.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.Header("X-Trace", "1"))

Headers

Headers sets multiple headers on a request or client.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.Headers(map[string]string{
	"X-Trace": "1",
	"Accept":  "application/json",
}))

JSON

JSON sets the request body as JSON.

type Payload struct {
	Name string `json:"name"`
}

c := httpx.New()
_ = httpx.Post[any, string](c, "https://example.com", nil, httpx.JSON(Payload{Name: "Ana"}))

Path

Path sets a path parameter by name.

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

c := httpx.New()
_ = httpx.Get[User](c, "https://example.com/users/{id}", httpx.Path("id", 42))

Paths

Paths sets multiple path parameters.

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

c := httpx.New()
_ = httpx.Get[User](c, "https://example.com/orgs/{org}/users/{id}", httpx.Paths(map[string]any{
	"org": "goforj",
	"id":  42,
}))

Queries

Queries adds multiple query parameters.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com/search", httpx.Queries(map[string]string{
	"q":  "go",
	"ok": "1",
}))

Query

Query adds query parameters as key/value pairs.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com/search", httpx.Query("q", "go", "ok", "1"))

Timeout

Timeout sets a per-request timeout using context cancellation.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.Timeout(2*time.Second))

Requests

Delete

Delete issues a DELETE request using the provided client.

type DeleteResponse struct {
	OK bool `json:"ok"`
}

c := httpx.New()
res := httpx.Delete[DeleteResponse](c, "https://api.example.com/users/1")
_, _ = res.Body, res.Err

Get

Get issues a GET request using the provided client.

type PullRequest struct {
	Number int    `json:"number"`
	Title  string `json:"title"`
}

c := httpx.New(httpx.Header("Accept", "application/vnd.github+json"))
res := httpx.Get[[]PullRequest](c, "https://api.github.com/repos/goforj/httpx/pulls")
if res.Err != nil {
	return
}
godump.Dump(res.Body)

Patch

Patch issues a PATCH request using the provided client.

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

c := httpx.New()
res := httpx.Patch[UpdateUser, User](c, "https://api.example.com/users/1", UpdateUser{Name: "Ana"})
_, _ = res.Body, res.Err

Post

Post issues a POST request using the provided client.

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

c := httpx.New()
res := httpx.Post[CreateUser, User](c, "https://api.example.com/users", CreateUser{Name: "Ana"})
_, _ = res.Body, res.Err

Put

Put issues a PUT request using the provided client.

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

c := httpx.New()
res := httpx.Put[UpdateUser, User](c, "https://api.example.com/users/1", UpdateUser{Name: "Ana"})
_, _ = res.Body, res.Err

Requests (Context)

DeleteCtx

DeleteCtx issues a DELETE request using the provided client and context.

type DeleteResponse struct {
	OK bool `json:"ok"`
}

c := httpx.New()
ctx := context.Background()
res := httpx.DeleteCtx[DeleteResponse](c, ctx, "https://api.example.com/users/1")
_, _ = res.Body, res.Err

GetCtx

GetCtx issues a GET request using the provided client and context.

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

c := httpx.New()
ctx := context.Background()
res := httpx.GetCtx[User](c, ctx, "https://api.example.com/users/1")
_, _ = res.Body, res.Err

PatchCtx

PatchCtx issues a PATCH request using the provided client and context.

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

c := httpx.New()
ctx := context.Background()
res := httpx.PatchCtx[UpdateUser, User](c, ctx, "https://api.example.com/users/1", UpdateUser{Name: "Ana"})
_, _ = res.Body, res.Err

PostCtx

PostCtx issues a POST request using the provided client and context.

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

c := httpx.New()
ctx := context.Background()
res := httpx.PostCtx[CreateUser, User](c, ctx, "https://api.example.com/users", CreateUser{Name: "Ana"})
_, _ = res.Body, res.Err

PutCtx

PutCtx issues a PUT request using the provided client and context.

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

c := httpx.New()
ctx := context.Background()
res := httpx.PutCtx[UpdateUser, User](c, ctx, "https://api.example.com/users/1", UpdateUser{Name: "Ana"})
_, _ = res.Body, res.Err

Retry

RetryBackoff

RetryBackoff sets a capped exponential backoff retry interval for a request.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.RetryBackoff(100*time.Millisecond, 2*time.Second))

RetryCondition

RetryCondition sets the retry condition for a request.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.RetryCondition(func(resp *req.Response, _ error) bool {
	return resp != nil && resp.StatusCode == 503
}))

RetryCount

RetryCount enables retry for a request and sets the maximum retry count.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.RetryCount(2))

RetryFixedInterval

RetryFixedInterval sets a fixed retry interval for a request.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.RetryFixedInterval(200*time.Millisecond))

RetryHook

RetryHook registers a retry hook for a request.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.RetryHook(func(_ *req.Response, _ error) {}))

RetryInterval

RetryInterval sets a custom retry interval function for a request.

c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.RetryInterval(func(_ *req.Response, attempt int) time.Duration {
	return time.Duration(attempt) * 100 * time.Millisecond
}))

Retry (Client)

Retry

Retry applies a custom retry configuration to the client.

c := httpx.New(httpx.Retry(func(rc *req.Client) {
	rc.SetCommonRetryCount(2)
}))
_ = c

Upload Options

File

File attaches a file from disk as multipart form data.

c := httpx.New()
_ = httpx.Post[any, string](c, "https://example.com/upload", nil, httpx.File("file", "/tmp/report.txt"))

FileBytes

FileBytes attaches a file from bytes as multipart form data.

c := httpx.New()
_ = httpx.Post[any, string](c, "https://example.com/upload", nil, httpx.FileBytes("file", "report.txt", []byte("hello")))

FileReader

FileReader attaches a file from a reader as multipart form data.

c := httpx.New()
_ = httpx.Post[any, string](c, "https://example.com/upload", nil, httpx.FileReader("file", "report.txt", strings.NewReader("hello")))

Files

Files attaches multiple files from disk as multipart form data.

c := httpx.New()
_ = httpx.Post[any, string](c, "https://example.com/upload", nil, httpx.Files(map[string]string{
	"fileA": "/tmp/a.txt",
	"fileB": "/tmp/b.txt",
}))

UploadCallback

UploadCallback registers a callback for upload progress.

c := httpx.New()
_ = httpx.Post[any, string](c, "https://example.com/upload", nil,
	httpx.File("file", "/tmp/report.bin"),
	httpx.UploadCallback(func(info req.UploadInfo) {
		percent := float64(info.UploadedSize) / float64(info.FileSize) * 100
		fmt.Printf("\rprogress: %.1f%%", percent)
		if info.FileSize > 0 && info.UploadedSize >= info.FileSize {
			fmt.Print("\n")
		}
	}),
)

UploadCallbackWithInterval

UploadCallbackWithInterval registers a callback for upload progress with a minimum interval.

c := httpx.New()
_ = httpx.Post[any, string](c, "https://example.com/upload", nil,
	httpx.File("file", "/tmp/report.bin"),
	httpx.UploadCallbackWithInterval(func(info req.UploadInfo) {
		percent := float64(info.UploadedSize) / float64(info.FileSize) * 100
		fmt.Printf("\rprogress: %.1f%% (%.0f bytes)", percent, float64(info.UploadedSize))
		if info.FileSize > 0 && info.UploadedSize >= info.FileSize {
			fmt.Print("\n")
		}
	}, 200*time.Millisecond),
)

UploadProgress

UploadProgress enables a default progress spinner and bar for uploads.

c := httpx.New()
_ = httpx.Post[any, string](c, "https://example.com/upload", nil,
	httpx.File("file", "/tmp/report.bin"),
	httpx.UploadProgress(),
)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages