From 951493debe401ffe7c0ca2b7e6f2c6e51beb14f0 Mon Sep 17 00:00:00 2001
From: Chris Miles
Date: Sun, 28 Dec 2025 20:35:45 -0600
Subject: [PATCH 1/5] feat: add proxy/cookie/redirect + trace helpers and
HEAD/OPTIONS requests
---
README.md | 120 ++++++++++++++++++++++++++++++++++--
client.go | 66 ++++++++++++++++++--
client_test.go | 32 ++++++++++
docs/examplegen/main.go | 1 +
examples/cookiejar/main.go | 18 ++++++
examples/head/main.go | 15 +++++
examples/headctx/main.go | 19 ++++++
examples/options/main.go | 15 +++++
examples/optionsctx/main.go | 19 ++++++
examples/proxy/main.go | 14 +++++
examples/proxyfunc/main.go | 17 +++++
examples/redirect/main.go | 17 +++++
examples/trace/main.go | 14 +++++
examples/traceall/main.go | 14 +++++
options_client.go | 83 +++++++++++++++++++++++++
options_client_test.go | 50 +++++++++++++++
options_debug.go | 36 +++++++++++
options_debug_test.go | 17 +++++
18 files changed, 557 insertions(+), 10 deletions(-)
create mode 100644 examples/cookiejar/main.go
create mode 100644 examples/head/main.go
create mode 100644 examples/headctx/main.go
create mode 100644 examples/options/main.go
create mode 100644 examples/optionsctx/main.go
create mode 100644 examples/proxy/main.go
create mode 100644 examples/proxyfunc/main.go
create mode 100644 examples/redirect/main.go
create mode 100644 examples/trace/main.go
create mode 100644 examples/traceall/main.go
diff --git a/README.md b/README.md
index d041e21..3d24020 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ It keeps req's power and escape hatches, while making the 90% use case feel effo
-
+
@@ -69,6 +69,16 @@ func main() {
}
```
+## Browser Profiles
+
+Browser profiles provide a simple way to match common client behavior without exposing low-level details.
+Internally, profiles may apply transport and protocol settings as needed, but those details are intentionally abstracted.
+
+```go
+c := httpx.New(httpx.AsChrome())
+_ = c
+```
+
## Use Any req Feature
**httpx** is built on top of the incredible [req](https://github.com/imroc/req) library, and you can always drop down to it when you need something beyond httpx’s helpers. That means every example in req’s docs is available to you with `c.Req()` or `c.Raw()`.
@@ -88,6 +98,9 @@ rc.EnableTraceAll()
See the full req documentation here: https://req.cool/docs/prologue/quickstart/
+Most users will only need the high-level APIs (browser profiles, request composition, retries, uploads).
+When you need deep control over headers, transports, or protocol behavior, `req` is always there.
+
## Options in Practice
```go
@@ -129,14 +142,14 @@ They are compiled by `example_compile_test.go` to keep docs and code in sync.
| **Auth** | [Auth](#auth) [Basic](#basic) [Bearer](#bearer) |
| **Browser Profiles** | [AsChrome](#aschrome) [AsFirefox](#asfirefox) [AsMobile](#asmobile) [AsSafari](#assafari) |
| **Client** | [Default](#default) [New](#new) [Raw](#raw) [Req](#req) |
-| **Client Options** | [BaseURL](#baseurl) [ErrorMapper](#errormapper) [Middleware](#middleware) [Transport](#transport) |
-| **Debugging** | [Dump](#dump) [DumpAll](#dumpall) [DumpEachRequest](#dumpeachrequest) [DumpEachRequestTo](#dumpeachrequestto) [DumpTo](#dumpto) [DumpToFile](#dumptofile) |
+| **Client Options** | [BaseURL](#baseurl) [CookieJar](#cookiejar) [ErrorMapper](#errormapper) [Middleware](#middleware) [Proxy](#proxy) [ProxyFunc](#proxyfunc) [Redirect](#redirect) [Transport](#transport) |
+| **Debugging** | [Dump](#dump) [DumpAll](#dumpall) [DumpEachRequest](#dumpeachrequest) [DumpEachRequestTo](#dumpeachrequestto) [DumpTo](#dumpto) [DumpToFile](#dumptofile) [Trace](#trace) [TraceAll](#traceall) |
| **Download Options** | [OutputFile](#outputfile) |
| **Errors** | [Error](#error) |
| **Request Composition** | [Body](#body) [Form](#form) [Header](#header) [Headers](#headers) [JSON](#json) [Path](#path) [Paths](#paths) [Queries](#queries) [Query](#query) [UserAgent](#useragent) |
| **Request Control** | [Before](#before) [Timeout](#timeout) |
-| **Requests** | [Delete](#delete) [Get](#get) [Patch](#patch) [Post](#post) [Put](#put) |
-| **Requests (Context)** | [DeleteCtx](#deletectx) [GetCtx](#getctx) [PatchCtx](#patchctx) [PostCtx](#postctx) [PutCtx](#putctx) |
+| **Requests** | [Delete](#delete) [Get](#get) [Head](#head) [Options](#options) [Patch](#patch) [Post](#post) [Put](#put) |
+| **Requests (Context)** | [DeleteCtx](#deletectx) [GetCtx](#getctx) [HeadCtx](#headctx) [OptionsCtx](#optionsctx) [PatchCtx](#patchctx) [PostCtx](#postctx) [PutCtx](#putctx) |
| **Retry** | [RetryBackoff](#retrybackoff) [RetryCondition](#retrycondition) [RetryCount](#retrycount) [RetryFixedInterval](#retryfixedinterval) [RetryHook](#retryhook) [RetryInterval](#retryinterval) |
| **Retry (Client)** | [Retry](#retry) |
| **Upload Options** | [File](#file) [FileBytes](#filebytes) [FileReader](#filereader) [Files](#files) [UploadCallback](#uploadcallback) [UploadCallbackWithInterval](#uploadcallbackwithinterval) [UploadProgress](#uploadprogress) |
@@ -292,6 +305,16 @@ c := httpx.New(httpx.BaseURL("https://api.example.com"))
_ = c
```
+### CookieJar
+
+CookieJar sets the cookie jar for the client.
+
+```go
+jar, _ := cookiejar.New(nil)
+c := httpx.New(httpx.CookieJar(jar))
+_ = c
+```
+
### ErrorMapper
ErrorMapper sets a custom error mapper for non-2xx responses.
@@ -315,6 +338,33 @@ c := httpx.New(httpx.Middleware(func(_ *req.Client, r *req.Request) error {
_ = c
```
+### Proxy
+
+Proxy sets a proxy URL for the client.
+
+```go
+c := httpx.New(httpx.Proxy("http://localhost:8080"))
+_ = c
+```
+
+### ProxyFunc
+
+ProxyFunc sets a proxy function for the client.
+
+```go
+c := httpx.New(httpx.ProxyFunc(http.ProxyFromEnvironment))
+_ = c
+```
+
+### Redirect
+
+Redirect sets the redirect policy for the client.
+
+```go
+c := httpx.New(httpx.Redirect(req.NoRedirectPolicy()))
+_ = c
+```
+
### Transport
Transport wraps the underlying transport with a custom RoundTripper.
@@ -383,6 +433,24 @@ c := httpx.New()
_ = httpx.Get[string](c, "https://example.com", httpx.DumpToFile("httpx.dump"))
```
+### Trace
+
+Trace enables req's request-level trace output.
+
+```go
+c := httpx.New()
+_ = httpx.Get[string](c, "https://example.com", httpx.Trace())
+```
+
+### TraceAll
+
+TraceAll enables req's client-level trace output for all requests.
+
+```go
+c := httpx.New(httpx.TraceAll())
+_ = c
+```
+
## Download Options
### OutputFile
@@ -588,6 +656,26 @@ if res.Err != nil {
godump.Dump(res.Body)
```
+### Head
+
+Head issues a HEAD request using the provided client.
+
+```go
+c := httpx.New()
+res := httpx.Head[string](c, "https://example.com")
+_ = res
+```
+
+### Options
+
+Options issues an OPTIONS request using the provided client.
+
+```go
+c := httpx.New()
+res := httpx.Options[string](c, "https://example.com")
+_ = res
+```
+
### Patch
Patch issues a PATCH request using the provided client.
@@ -671,6 +759,28 @@ res := httpx.GetCtx[User](c, ctx, "https://api.example.com/users/1")
_, _ = res.Body, res.Err
```
+### HeadCtx
+
+HeadCtx issues a HEAD request using the provided client and context.
+
+```go
+c := httpx.New()
+ctx := context.Background()
+res := httpx.HeadCtx[string](c, ctx, "https://example.com")
+_ = res
+```
+
+### OptionsCtx
+
+OptionsCtx issues an OPTIONS request using the provided client and context.
+
+```go
+c := httpx.New()
+ctx := context.Background()
+res := httpx.OptionsCtx[string](c, ctx, "https://example.com")
+_ = res
+```
+
### PatchCtx
PatchCtx issues a PATCH request using the provided client and context.
diff --git a/client.go b/client.go
index 2988144..278a657 100644
--- a/client.go
+++ b/client.go
@@ -216,6 +216,30 @@ func Delete[T any](client *Client, url string, opts ...Option) Result[T] {
return do[T](client, nil, methodDelete, url, nil, opts)
}
+// Head issues a HEAD request using the provided client.
+// @group Requests
+//
+// Example: HEAD request
+//
+// c := httpx.New()
+// res := httpx.Head[string](c, "https://example.com")
+// _ = res
+func Head[T any](client *Client, url string, opts ...Option) Result[T] {
+ return do[T](client, nil, methodHead, url, nil, opts)
+}
+
+// Options issues an OPTIONS request using the provided client.
+// @group Requests
+//
+// Example: OPTIONS request
+//
+// c := httpx.New()
+// res := httpx.Options[string](c, "https://example.com")
+// _ = res
+func Options[T any](client *Client, url string, opts ...Option) Result[T] {
+ return do[T](client, nil, methodOptions, url, nil, opts)
+}
+
// GetCtx issues a GET request using the provided client and context.
// @group Requests (Context)
//
@@ -310,6 +334,32 @@ func DeleteCtx[T any](client *Client, ctx context.Context, url string, opts ...O
return do[T](client, ctx, methodDelete, url, nil, opts)
}
+// HeadCtx issues a HEAD request using the provided client and context.
+// @group Requests (Context)
+//
+// Example: context-aware HEAD
+//
+// c := httpx.New()
+// ctx := context.Background()
+// res := httpx.HeadCtx[string](c, ctx, "https://example.com")
+// _ = res
+func HeadCtx[T any](client *Client, ctx context.Context, url string, opts ...Option) Result[T] {
+ return do[T](client, ctx, methodHead, url, nil, opts)
+}
+
+// OptionsCtx issues an OPTIONS request using the provided client and context.
+// @group Requests (Context)
+//
+// Example: context-aware OPTIONS
+//
+// c := httpx.New()
+// ctx := context.Background()
+// res := httpx.OptionsCtx[string](c, ctx, "https://example.com")
+// _ = res
+func OptionsCtx[T any](client *Client, ctx context.Context, url string, opts ...Option) Result[T] {
+ return do[T](client, ctx, methodOptions, url, nil, opts)
+}
+
func do[T any](client *Client, ctx context.Context, method, url string, body any, opts []Option) Result[T] {
var res Result[T]
@@ -370,11 +420,13 @@ func (c *Client) mapError(resp *req.Response) error {
}
const (
- methodGet = "GET"
- methodPost = "POST"
- methodPut = "PUT"
- methodPatch = "PATCH"
- methodDelete = "DELETE"
+ methodGet = "GET"
+ methodPost = "POST"
+ methodPut = "PUT"
+ methodPatch = "PATCH"
+ methodDelete = "DELETE"
+ methodHead = "HEAD"
+ methodOptions = "OPTIONS"
)
func send(r *req.Request, method, url string) (*req.Response, error) {
@@ -389,6 +441,10 @@ func send(r *req.Request, method, url string) (*req.Response, error) {
return r.Patch(url)
case methodDelete:
return r.Delete(url)
+ case methodHead:
+ return r.Head(url)
+ case methodOptions:
+ return r.Options(url)
default:
return nil, fmt.Errorf("httpx: unsupported method %s", method)
}
diff --git a/client_test.go b/client_test.go
index cd21fca..02c8ddf 100644
--- a/client_test.go
+++ b/client_test.go
@@ -119,6 +119,38 @@ func TestErrorMapper(t *testing.T) {
}
}
+func TestHeadRequest(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodHead {
+ t.Fatalf("method = %s", r.Method)
+ }
+ w.WriteHeader(http.StatusOK)
+ }))
+ t.Cleanup(server.Close)
+
+ client := New()
+ res := Head[string](client, server.URL)
+ if res.Err != nil {
+ t.Fatalf("unexpected error: %v", res.Err)
+ }
+}
+
+func TestOptionsRequest(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodOptions {
+ t.Fatalf("method = %s", r.Method)
+ }
+ w.WriteHeader(http.StatusOK)
+ }))
+ t.Cleanup(server.Close)
+
+ client := New()
+ res := Options[string](client, server.URL)
+ if res.Err != nil {
+ t.Fatalf("unexpected error: %v", res.Err)
+ }
+}
+
func TestOptionsApplied(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/users/123" {
diff --git a/docs/examplegen/main.go b/docs/examplegen/main.go
index e0a6af8..28941cf 100644
--- a/docs/examplegen/main.go
+++ b/docs/examplegen/main.go
@@ -390,6 +390,7 @@ func writeMain(base string, fd *FuncDoc, importPath string) error {
"httptest.": "net/http/httptest",
"context.": "context",
"regexp.": "regexp",
+ "cookiejar.": "net/http/cookiejar",
"redis.": "github.com/redis/go-redis/v9",
"time.": "time",
"gocron": "github.com/go-co-op/gocron/v2",
diff --git a/examples/cookiejar/main.go b/examples/cookiejar/main.go
new file mode 100644
index 0000000..b2d8535
--- /dev/null
+++ b/examples/cookiejar/main.go
@@ -0,0 +1,18 @@
+//go:build ignore
+// +build ignore
+
+package main
+
+import (
+ "github.com/goforj/httpx"
+ "net/http/cookiejar"
+)
+
+func main() {
+ // CookieJar sets the cookie jar for the client.
+
+ // Example: set cookie jar
+ jar, _ := cookiejar.New(nil)
+ c := httpx.New(httpx.CookieJar(jar))
+ _ = c
+}
diff --git a/examples/head/main.go b/examples/head/main.go
new file mode 100644
index 0000000..edbe107
--- /dev/null
+++ b/examples/head/main.go
@@ -0,0 +1,15 @@
+//go:build ignore
+// +build ignore
+
+package main
+
+import "github.com/goforj/httpx"
+
+func main() {
+ // Head issues a HEAD request using the provided client.
+
+ // Example: HEAD request
+ c := httpx.New()
+ res := httpx.Head[string](c, "https://example.com")
+ _ = res
+}
diff --git a/examples/headctx/main.go b/examples/headctx/main.go
new file mode 100644
index 0000000..bdb38b9
--- /dev/null
+++ b/examples/headctx/main.go
@@ -0,0 +1,19 @@
+//go:build ignore
+// +build ignore
+
+package main
+
+import (
+ "context"
+ "github.com/goforj/httpx"
+)
+
+func main() {
+ // HeadCtx issues a HEAD request using the provided client and context.
+
+ // Example: context-aware HEAD
+ c := httpx.New()
+ ctx := context.Background()
+ res := httpx.HeadCtx[string](c, ctx, "https://example.com")
+ _ = res
+}
diff --git a/examples/options/main.go b/examples/options/main.go
new file mode 100644
index 0000000..c49d913
--- /dev/null
+++ b/examples/options/main.go
@@ -0,0 +1,15 @@
+//go:build ignore
+// +build ignore
+
+package main
+
+import "github.com/goforj/httpx"
+
+func main() {
+ // Options issues an OPTIONS request using the provided client.
+
+ // Example: OPTIONS request
+ c := httpx.New()
+ res := httpx.Options[string](c, "https://example.com")
+ _ = res
+}
diff --git a/examples/optionsctx/main.go b/examples/optionsctx/main.go
new file mode 100644
index 0000000..b5656d6
--- /dev/null
+++ b/examples/optionsctx/main.go
@@ -0,0 +1,19 @@
+//go:build ignore
+// +build ignore
+
+package main
+
+import (
+ "context"
+ "github.com/goforj/httpx"
+)
+
+func main() {
+ // OptionsCtx issues an OPTIONS request using the provided client and context.
+
+ // Example: context-aware OPTIONS
+ c := httpx.New()
+ ctx := context.Background()
+ res := httpx.OptionsCtx[string](c, ctx, "https://example.com")
+ _ = res
+}
diff --git a/examples/proxy/main.go b/examples/proxy/main.go
new file mode 100644
index 0000000..9b4549a
--- /dev/null
+++ b/examples/proxy/main.go
@@ -0,0 +1,14 @@
+//go:build ignore
+// +build ignore
+
+package main
+
+import "github.com/goforj/httpx"
+
+func main() {
+ // Proxy sets a proxy URL for the client.
+
+ // Example: set proxy URL
+ c := httpx.New(httpx.Proxy("http://localhost:8080"))
+ _ = c
+}
diff --git a/examples/proxyfunc/main.go b/examples/proxyfunc/main.go
new file mode 100644
index 0000000..3101bc0
--- /dev/null
+++ b/examples/proxyfunc/main.go
@@ -0,0 +1,17 @@
+//go:build ignore
+// +build ignore
+
+package main
+
+import (
+ "github.com/goforj/httpx"
+ "net/http"
+)
+
+func main() {
+ // ProxyFunc sets a proxy function for the client.
+
+ // Example: set proxy function
+ c := httpx.New(httpx.ProxyFunc(http.ProxyFromEnvironment))
+ _ = c
+}
diff --git a/examples/redirect/main.go b/examples/redirect/main.go
new file mode 100644
index 0000000..a10867f
--- /dev/null
+++ b/examples/redirect/main.go
@@ -0,0 +1,17 @@
+//go:build ignore
+// +build ignore
+
+package main
+
+import (
+ "github.com/goforj/httpx"
+ "github.com/imroc/req/v3"
+)
+
+func main() {
+ // Redirect sets the redirect policy for the client.
+
+ // Example: disable redirects
+ c := httpx.New(httpx.Redirect(req.NoRedirectPolicy()))
+ _ = c
+}
diff --git a/examples/trace/main.go b/examples/trace/main.go
new file mode 100644
index 0000000..533e2a4
--- /dev/null
+++ b/examples/trace/main.go
@@ -0,0 +1,14 @@
+//go:build ignore
+// +build ignore
+
+package main
+
+import "github.com/goforj/httpx"
+
+func main() {
+ // Trace enables req's request-level trace output.
+
+ // Example: trace a single request
+ c := httpx.New()
+ _ = httpx.Get[string](c, "https://example.com", httpx.Trace())
+}
diff --git a/examples/traceall/main.go b/examples/traceall/main.go
new file mode 100644
index 0000000..5d3f4ca
--- /dev/null
+++ b/examples/traceall/main.go
@@ -0,0 +1,14 @@
+//go:build ignore
+// +build ignore
+
+package main
+
+import "github.com/goforj/httpx"
+
+func main() {
+ // TraceAll enables req's client-level trace output for all requests.
+
+ // Example: trace all requests
+ c := httpx.New(httpx.TraceAll())
+ _ = c
+}
diff --git a/options_client.go b/options_client.go
index f43fe54..09e4991 100644
--- a/options_client.go
+++ b/options_client.go
@@ -2,6 +2,7 @@ package httpx
import (
"net/http"
+ "net/url"
"github.com/imroc/req/v3"
)
@@ -89,3 +90,85 @@ func (b OptionBuilder) ErrorMapper(fn ErrorMapperFunc) OptionBuilder {
c.errorMapper = fn
}))
}
+
+// Proxy sets a proxy URL for the client.
+// @group Client Options
+//
+// Applies to client configuration only.
+// Example: set proxy URL
+//
+// c := httpx.New(httpx.Proxy("http://localhost:8080"))
+// _ = c
+func Proxy(proxyURL string) OptionBuilder {
+ return OptionBuilder{}.Proxy(proxyURL)
+}
+
+func (b OptionBuilder) Proxy(proxyURL string) OptionBuilder {
+ return b.add(clientOnly(func(c *Client) {
+ if proxyURL == "" {
+ return
+ }
+ c.req.SetProxyURL(proxyURL)
+ }))
+}
+
+// ProxyFunc sets a proxy function for the client.
+// @group Client Options
+//
+// Applies to client configuration only.
+// Example: set proxy function
+//
+// c := httpx.New(httpx.ProxyFunc(http.ProxyFromEnvironment))
+// _ = c
+func ProxyFunc(fn func(*http.Request) (*url.URL, error)) OptionBuilder {
+ return OptionBuilder{}.ProxyFunc(fn)
+}
+
+func (b OptionBuilder) ProxyFunc(fn func(*http.Request) (*url.URL, error)) OptionBuilder {
+ if fn == nil {
+ return b
+ }
+ return b.add(clientOnly(func(c *Client) {
+ c.req.SetProxy(fn)
+ }))
+}
+
+// CookieJar sets the cookie jar for the client.
+// @group Client Options
+//
+// Applies to client configuration only.
+// Example: set cookie jar
+//
+// jar, _ := cookiejar.New(nil)
+// c := httpx.New(httpx.CookieJar(jar))
+// _ = c
+func CookieJar(jar http.CookieJar) OptionBuilder {
+ return OptionBuilder{}.CookieJar(jar)
+}
+
+func (b OptionBuilder) CookieJar(jar http.CookieJar) OptionBuilder {
+ return b.add(clientOnly(func(c *Client) {
+ c.req.SetCookieJar(jar)
+ }))
+}
+
+// Redirect sets the redirect policy for the client.
+// @group Client Options
+//
+// Applies to client configuration only.
+// Example: disable redirects
+//
+// c := httpx.New(httpx.Redirect(req.NoRedirectPolicy()))
+// _ = c
+func Redirect(policies ...req.RedirectPolicy) OptionBuilder {
+ return OptionBuilder{}.Redirect(policies...)
+}
+
+func (b OptionBuilder) Redirect(policies ...req.RedirectPolicy) OptionBuilder {
+ return b.add(clientOnly(func(c *Client) {
+ if len(policies) == 0 {
+ return
+ }
+ c.req.SetRedirectPolicy(policies...)
+ }))
+}
diff --git a/options_client_test.go b/options_client_test.go
index 478be19..a745875 100644
--- a/options_client_test.go
+++ b/options_client_test.go
@@ -5,7 +5,10 @@ import (
"errors"
"io"
"net/http"
+ "net/http/cookiejar"
"net/http/httptest"
+ "net/url"
+ "reflect"
"testing"
"time"
@@ -129,6 +132,53 @@ func TestWithErrorMapper(t *testing.T) {
}
}
+func TestWithProxy(t *testing.T) {
+ c := New(Proxy("http://localhost:8080"))
+ if c.req.Transport.Options.Proxy == nil {
+ t.Fatalf("expected proxy to be set")
+ }
+}
+
+func TestWithProxyFunc(t *testing.T) {
+ c := New(ProxyFunc(nil))
+ if c == nil {
+ t.Fatalf("expected client")
+ }
+
+ fn := func(req *http.Request) (*url.URL, error) {
+ return http.ProxyFromEnvironment(req)
+ }
+ c = New(ProxyFunc(fn))
+ if c.req.Transport.Options.Proxy == nil {
+ t.Fatalf("expected proxy func to be set")
+ }
+}
+
+func TestWithCookieJar(t *testing.T) {
+ jar, err := cookiejar.New(nil)
+ if err != nil {
+ t.Fatalf("cookie jar: %v", err)
+ }
+ c := New(CookieJar(jar))
+ got := reflect.ValueOf(c.req).Elem().FieldByName("httpClient").Elem().FieldByName("Jar")
+ if got.IsNil() {
+ t.Fatalf("expected cookie jar to be set")
+ }
+}
+
+func TestWithRedirect(t *testing.T) {
+ c := New(Redirect())
+ if c == nil {
+ t.Fatalf("expected client")
+ }
+
+ c = New(Redirect(req.NoRedirectPolicy()))
+ got := reflect.ValueOf(c.req).Elem().FieldByName("httpClient").Elem().FieldByName("CheckRedirect")
+ if got.IsNil() {
+ t.Fatalf("expected redirect policy to be set")
+ }
+}
+
type roundTripperFunc func(*http.Request) (*http.Response, error)
func (rt roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
diff --git a/options_debug.go b/options_debug.go
index f7c268b..c8469bc 100644
--- a/options_debug.go
+++ b/options_debug.go
@@ -126,3 +126,39 @@ func (b OptionBuilder) DumpEachRequestTo(output io.Writer) OptionBuilder {
})
}))
}
+
+// Trace enables req's request-level trace output.
+// @group Debugging
+//
+// Applies to individual requests only.
+// Example: trace a single request
+//
+// c := httpx.New()
+// _ = httpx.Get[string](c, "https://example.com", httpx.Trace())
+func Trace() OptionBuilder {
+ return OptionBuilder{}.Trace()
+}
+
+func (b OptionBuilder) Trace() OptionBuilder {
+ return b.add(requestOnly(func(r *req.Request) {
+ r.EnableTrace()
+ }))
+}
+
+// TraceAll enables req's client-level trace output for all requests.
+// @group Debugging
+//
+// Applies to the client configuration only.
+// Example: trace all requests
+//
+// c := httpx.New(httpx.TraceAll())
+// _ = c
+func TraceAll() OptionBuilder {
+ return OptionBuilder{}.TraceAll()
+}
+
+func (b OptionBuilder) TraceAll() OptionBuilder {
+ return b.add(clientOnly(func(c *Client) {
+ c.req.EnableTraceAll()
+ }))
+}
diff --git a/options_debug_test.go b/options_debug_test.go
index acf824e..74462a5 100644
--- a/options_debug_test.go
+++ b/options_debug_test.go
@@ -108,3 +108,20 @@ func TestDumpEachRequestFunction(t *testing.T) {
t.Fatalf("request failed: %v", res.Err)
}
}
+
+func TestTrace(t *testing.T) {
+ r := req.C().R()
+ Trace().applyRequest(r)
+ traceField := reflect.ValueOf(r).Elem().FieldByName("trace")
+ if traceField.IsNil() {
+ t.Fatalf("expected trace to be enabled")
+ }
+}
+
+func TestTraceAll(t *testing.T) {
+ c := New(TraceAll())
+ traceField := reflect.ValueOf(c.Req()).Elem().FieldByName("trace")
+ if !traceField.Bool() {
+ t.Fatalf("expected trace to be enabled")
+ }
+}
From 54e9b8cb8c2c9f4f77c905ce10a10aa19c7834dd Mon Sep 17 00:00:00 2001
From: Chris Miles
Date: Sun, 28 Dec 2025 20:51:40 -0600
Subject: [PATCH 2/5] chore: code cov
---
README.md | 2 +-
client_test.go | 33 +++++++++++++++++++++++++++++++++
options_client_test.go | 7 +++++++
3 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 3d24020..fc81b54 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ It keeps req's power and escape hatches, while making the 90% use case feel effo
-
+
diff --git a/client_test.go b/client_test.go
index 02c8ddf..bb1ae9d 100644
--- a/client_test.go
+++ b/client_test.go
@@ -151,6 +151,39 @@ func TestOptionsRequest(t *testing.T) {
}
}
+func TestHeadCtxRequest(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodHead {
+ t.Fatalf("method = %s", r.Method)
+ }
+ w.WriteHeader(http.StatusOK)
+ }))
+ t.Cleanup(server.Close)
+
+ client := New()
+ ctx := context.Background()
+ res := HeadCtx[string](client, ctx, server.URL)
+ if res.Err != nil {
+ t.Fatalf("unexpected error: %v", res.Err)
+ }
+}
+
+func TestOptionsCtxRequest(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodOptions {
+ t.Fatalf("method = %s", r.Method)
+ }
+ w.WriteHeader(http.StatusOK)
+ }))
+ t.Cleanup(server.Close)
+
+ client := New()
+ ctx := context.Background()
+ res := OptionsCtx[string](client, ctx, server.URL)
+ if res.Err != nil {
+ t.Fatalf("unexpected error: %v", res.Err)
+ }
+}
func TestOptionsApplied(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/users/123" {
diff --git a/options_client_test.go b/options_client_test.go
index a745875..ba7c211 100644
--- a/options_client_test.go
+++ b/options_client_test.go
@@ -139,6 +139,13 @@ func TestWithProxy(t *testing.T) {
}
}
+func TestWithProxyEmpty(t *testing.T) {
+ c := New(Proxy(""))
+ if c.req.Transport.Options.Proxy == nil {
+ t.Fatalf("expected proxy to remain set")
+ }
+}
+
func TestWithProxyFunc(t *testing.T) {
c := New(ProxyFunc(nil))
if c == nil {
From 3047e3421d93fccc41edb25ab657c19ff07a0aab Mon Sep 17 00:00:00 2001
From: Chris Miles
Date: Sun, 28 Dec 2025 20:59:43 -0600
Subject: [PATCH 3/5] docs: cookie example
---
README.md | 4 ++++
docs/examplegen/main.go | 1 +
examples/cookiejar/main.go | 8 +++++++-
options_client.go | 6 +++++-
4 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index fc81b54..21556b6 100644
--- a/README.md
+++ b/README.md
@@ -311,6 +311,10 @@ CookieJar sets the cookie jar for the client.
```go
jar, _ := cookiejar.New(nil)
+u, _ := url.Parse("https://example.com")
+jar.SetCookies(u, []*http.Cookie{
+ {Name: "session", Value: "abc123"},
+})
c := httpx.New(httpx.CookieJar(jar))
_ = c
```
diff --git a/docs/examplegen/main.go b/docs/examplegen/main.go
index 28941cf..59ac773 100644
--- a/docs/examplegen/main.go
+++ b/docs/examplegen/main.go
@@ -391,6 +391,7 @@ func writeMain(base string, fd *FuncDoc, importPath string) error {
"context.": "context",
"regexp.": "regexp",
"cookiejar.": "net/http/cookiejar",
+ "url.": "net/url",
"redis.": "github.com/redis/go-redis/v9",
"time.": "time",
"gocron": "github.com/go-co-op/gocron/v2",
diff --git a/examples/cookiejar/main.go b/examples/cookiejar/main.go
index b2d8535..0525ff0 100644
--- a/examples/cookiejar/main.go
+++ b/examples/cookiejar/main.go
@@ -5,14 +5,20 @@ package main
import (
"github.com/goforj/httpx"
+ "net/http"
"net/http/cookiejar"
+ "net/url"
)
func main() {
// CookieJar sets the cookie jar for the client.
- // Example: set cookie jar
+ // Example: set cookie jar and seed cookies
jar, _ := cookiejar.New(nil)
+ u, _ := url.Parse("https://example.com")
+ jar.SetCookies(u, []*http.Cookie{
+ {Name: "session", Value: "abc123"},
+ })
c := httpx.New(httpx.CookieJar(jar))
_ = c
}
diff --git a/options_client.go b/options_client.go
index 09e4991..b23340a 100644
--- a/options_client.go
+++ b/options_client.go
@@ -137,9 +137,13 @@ func (b OptionBuilder) ProxyFunc(fn func(*http.Request) (*url.URL, error)) Optio
// @group Client Options
//
// Applies to client configuration only.
-// Example: set cookie jar
+// Example: set cookie jar and seed cookies
//
// jar, _ := cookiejar.New(nil)
+// u, _ := url.Parse("https://example.com")
+// jar.SetCookies(u, []*http.Cookie{
+// {Name: "session", Value: "abc123"},
+// })
// c := httpx.New(httpx.CookieJar(jar))
// _ = c
func CookieJar(jar http.CookieJar) OptionBuilder {
From 9307845923bac3e570af78cff56f710cbd85dd2b Mon Sep 17 00:00:00 2001
From: Chris Miles
Date: Sun, 28 Dec 2025 21:12:01 -0600
Subject: [PATCH 4/5] docs: cleanup
---
README.md | 109 +++++++++++++++++++++-------
examples/auth/main.go | 8 +-
examples/basic/main.go | 8 +-
examples/bearer/main.go | 8 +-
examples/header/main.go | 8 +-
examples/headers/main.go | 11 ++-
examples/retrybackoff/main.go | 10 ++-
examples/retrycondition/main.go | 10 ++-
examples/retrycount/main.go | 10 ++-
examples/retryfixedinterval/main.go | 10 ++-
examples/retryhook/main.go | 8 +-
examples/retryinterval/main.go | 10 ++-
examples/timeout/main.go | 10 ++-
examples/useragent/main.go | 6 +-
options_auth.go | 24 ++++--
options_request.go | 35 +++++++--
options_retry.go | 58 +++++++++++----
17 files changed, 260 insertions(+), 83 deletions(-)
diff --git a/README.md b/README.md
index 21556b6..7e4873e 100644
--- a/README.md
+++ b/README.md
@@ -163,8 +163,12 @@ They are compiled by `example_compile_test.go` to keep docs and code in sync.
Auth sets the Authorization header using a scheme and token.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.Auth("Token", "abc123"))
+// Apply to all requests
+c := httpx.New(httpx.Auth("Token", "abc123"))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.Auth("Token", "abc123"))
```
### Basic
@@ -172,8 +176,12 @@ _ = httpx.Get[string](c, "https://example.com", httpx.Auth("Token", "abc123"))
Basic sets HTTP basic authentication headers.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.Basic("user", "pass"))
+// Apply to all requests
+c := httpx.New(httpx.Basic("user", "pass"))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.Basic("user", "pass"))
```
### Bearer
@@ -181,8 +189,12 @@ _ = httpx.Get[string](c, "https://example.com", httpx.Basic("user", "pass"))
Bearer sets the Authorization header with a bearer token.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.Bearer("token"))
+// Apply to all requests
+c := httpx.New(httpx.Bearer("token"))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.Bearer("token"))
```
## Browser Profiles
@@ -516,8 +528,12 @@ _ = httpx.Post[any, string](c, "https://example.com", nil, httpx.Form(map[string
Header sets a header on a request or client.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.Header("X-Trace", "1"))
+// Apply to all requests
+c := httpx.New(httpx.Header("X-Trace", "1"))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.Header("X-Trace", "1"))
```
### Headers
@@ -525,8 +541,15 @@ _ = httpx.Get[string](c, "https://example.com", httpx.Header("X-Trace", "1"))
Headers sets multiple headers on a request or client.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.Headers(map[string]string{
+// Apply to all requests
+c := httpx.New(httpx.Headers(map[string]string{
+ "X-Trace": "1",
+ "Accept": "application/json",
+}))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.Headers(map[string]string{
"X-Trace": "1",
"Accept": "application/json",
}))
@@ -600,8 +623,12 @@ _ = httpx.Get[string](c, "https://example.com/search", httpx.Query("q", "go", "o
UserAgent sets the User-Agent header on a request or client.
```go
+// Apply to all requests
c := httpx.New(httpx.UserAgent("my-app/1.0"))
-_ = httpx.Get[string](c, "https://example.com")
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.UserAgent("my-app/1.0"))
```
## Request Control
@@ -622,8 +649,12 @@ _ = httpx.Get[string](c, "https://example.com", httpx.Before(func(r *req.Request
Timeout sets a per-request timeout using context cancellation.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.Timeout(2*time.Second))
+// Apply to all requests
+c := httpx.New(httpx.Timeout(2 * time.Second))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.Timeout(2*time.Second))
```
## Requests
@@ -846,8 +877,12 @@ _, _ = res.Body, res.Err
RetryBackoff sets a capped exponential backoff retry interval for a request.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.RetryBackoff(100*time.Millisecond, 2*time.Second))
+// Apply to all requests
+c := httpx.New(httpx.RetryBackoff(100*time.Millisecond, 2*time.Second))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryBackoff(100*time.Millisecond, 2*time.Second))
```
### RetryCondition
@@ -855,8 +890,14 @@ _ = httpx.Get[string](c, "https://example.com", httpx.RetryBackoff(100*time.Mill
RetryCondition sets the retry condition for a request.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.RetryCondition(func(resp *req.Response, _ error) bool {
+// Apply to all requests
+c := httpx.New(httpx.RetryCondition(func(resp *req.Response, _ error) bool {
+ return resp != nil && resp.StatusCode == 503
+}))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryCondition(func(resp *req.Response, _ error) bool {
return resp != nil && resp.StatusCode == 503
}))
```
@@ -866,8 +907,12 @@ _ = httpx.Get[string](c, "https://example.com", httpx.RetryCondition(func(resp *
RetryCount enables retry for a request and sets the maximum retry count.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.RetryCount(2))
+// Apply to all requests
+c := httpx.New(httpx.RetryCount(2))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryCount(2))
```
### RetryFixedInterval
@@ -875,8 +920,12 @@ _ = httpx.Get[string](c, "https://example.com", httpx.RetryCount(2))
RetryFixedInterval sets a fixed retry interval for a request.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.RetryFixedInterval(200*time.Millisecond))
+// Apply to all requests
+c := httpx.New(httpx.RetryFixedInterval(200 * time.Millisecond))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryFixedInterval(200*time.Millisecond))
```
### RetryHook
@@ -884,8 +933,12 @@ _ = httpx.Get[string](c, "https://example.com", httpx.RetryFixedInterval(200*tim
RetryHook registers a retry hook for a request.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.RetryHook(func(_ *req.Response, _ error) {}))
+// Apply to all requests
+c := httpx.New(httpx.RetryHook(func(_ *req.Response, _ error) {}))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryHook(func(_ *req.Response, _ error) {}))
```
### RetryInterval
@@ -893,8 +946,14 @@ _ = httpx.Get[string](c, "https://example.com", httpx.RetryHook(func(_ *req.Resp
RetryInterval sets a custom retry interval function for a request.
```go
-c := httpx.New()
-_ = httpx.Get[string](c, "https://example.com", httpx.RetryInterval(func(_ *req.Response, attempt int) time.Duration {
+// Apply to all requests
+c := httpx.New(httpx.RetryInterval(func(_ *req.Response, attempt int) time.Duration {
+ return time.Duration(attempt) * 100 * time.Millisecond
+}))
+httpx.Get[string](c, "https://example.com")
+
+// Apply to a single request
+httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryInterval(func(_ *req.Response, attempt int) time.Duration {
return time.Duration(attempt) * 100 * time.Millisecond
}))
```
diff --git a/examples/auth/main.go b/examples/auth/main.go
index ff434fe..b906650 100644
--- a/examples/auth/main.go
+++ b/examples/auth/main.go
@@ -9,6 +9,10 @@ func main() {
// Auth sets the Authorization header using a scheme and token.
// Example: custom auth scheme
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.Auth("Token", "abc123"))
+ // Apply to all requests
+ c := httpx.New(httpx.Auth("Token", "abc123"))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.Auth("Token", "abc123"))
}
diff --git a/examples/basic/main.go b/examples/basic/main.go
index fdedc70..89dfea9 100644
--- a/examples/basic/main.go
+++ b/examples/basic/main.go
@@ -9,6 +9,10 @@ func main() {
// Basic sets HTTP basic authentication headers.
// Example: basic auth
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.Basic("user", "pass"))
+ // Apply to all requests
+ c := httpx.New(httpx.Basic("user", "pass"))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.Basic("user", "pass"))
}
diff --git a/examples/bearer/main.go b/examples/bearer/main.go
index dc8392f..e47ede6 100644
--- a/examples/bearer/main.go
+++ b/examples/bearer/main.go
@@ -9,6 +9,10 @@ func main() {
// Bearer sets the Authorization header with a bearer token.
// Example: bearer auth
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.Bearer("token"))
+ // Apply to all requests
+ c := httpx.New(httpx.Bearer("token"))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.Bearer("token"))
}
diff --git a/examples/header/main.go b/examples/header/main.go
index aa35934..9e7a712 100644
--- a/examples/header/main.go
+++ b/examples/header/main.go
@@ -9,6 +9,10 @@ func main() {
// Header sets a header on a request or client.
// Example: apply a header
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.Header("X-Trace", "1"))
+ // Apply to all requests
+ c := httpx.New(httpx.Header("X-Trace", "1"))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.Header("X-Trace", "1"))
}
diff --git a/examples/headers/main.go b/examples/headers/main.go
index a112875..3875ad5 100644
--- a/examples/headers/main.go
+++ b/examples/headers/main.go
@@ -9,8 +9,15 @@ func main() {
// Headers sets multiple headers on a request or client.
// Example: apply headers
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.Headers(map[string]string{
+ // Apply to all requests
+ c := httpx.New(httpx.Headers(map[string]string{
+ "X-Trace": "1",
+ "Accept": "application/json",
+ }))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.Headers(map[string]string{
"X-Trace": "1",
"Accept": "application/json",
}))
diff --git a/examples/retrybackoff/main.go b/examples/retrybackoff/main.go
index 475ede0..6e5657e 100644
--- a/examples/retrybackoff/main.go
+++ b/examples/retrybackoff/main.go
@@ -11,7 +11,11 @@ import (
func main() {
// RetryBackoff sets a capped exponential backoff retry interval for a request.
- // Example: request retry backoff
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.RetryBackoff(100*time.Millisecond, 2*time.Second))
+ // Example: retry backoff
+ // Apply to all requests
+ c := httpx.New(httpx.RetryBackoff(100*time.Millisecond, 2*time.Second))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryBackoff(100*time.Millisecond, 2*time.Second))
}
diff --git a/examples/retrycondition/main.go b/examples/retrycondition/main.go
index c862e89..fb792e3 100644
--- a/examples/retrycondition/main.go
+++ b/examples/retrycondition/main.go
@@ -12,8 +12,14 @@ func main() {
// RetryCondition sets the retry condition for a request.
// Example: retry on 503
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.RetryCondition(func(resp *req.Response, _ error) bool {
+ // Apply to all requests
+ c := httpx.New(httpx.RetryCondition(func(resp *req.Response, _ error) bool {
+ return resp != nil && resp.StatusCode == 503
+ }))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryCondition(func(resp *req.Response, _ error) bool {
return resp != nil && resp.StatusCode == 503
}))
}
diff --git a/examples/retrycount/main.go b/examples/retrycount/main.go
index c925e5f..a169180 100644
--- a/examples/retrycount/main.go
+++ b/examples/retrycount/main.go
@@ -8,7 +8,11 @@ import "github.com/goforj/httpx"
func main() {
// RetryCount enables retry for a request and sets the maximum retry count.
- // Example: request retry count
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.RetryCount(2))
+ // Example: retry count
+ // Apply to all requests
+ c := httpx.New(httpx.RetryCount(2))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryCount(2))
}
diff --git a/examples/retryfixedinterval/main.go b/examples/retryfixedinterval/main.go
index cfbb0da..e65e43a 100644
--- a/examples/retryfixedinterval/main.go
+++ b/examples/retryfixedinterval/main.go
@@ -11,7 +11,11 @@ import (
func main() {
// RetryFixedInterval sets a fixed retry interval for a request.
- // Example: request retry interval
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.RetryFixedInterval(200*time.Millisecond))
+ // Example: retry interval
+ // Apply to all requests
+ c := httpx.New(httpx.RetryFixedInterval(200 * time.Millisecond))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryFixedInterval(200*time.Millisecond))
}
diff --git a/examples/retryhook/main.go b/examples/retryhook/main.go
index c0cbf53..881c752 100644
--- a/examples/retryhook/main.go
+++ b/examples/retryhook/main.go
@@ -12,6 +12,10 @@ func main() {
// RetryHook registers a retry hook for a request.
// Example: hook on retry
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.RetryHook(func(_ *req.Response, _ error) {}))
+ // Apply to all requests
+ c := httpx.New(httpx.RetryHook(func(_ *req.Response, _ error) {}))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryHook(func(_ *req.Response, _ error) {}))
}
diff --git a/examples/retryinterval/main.go b/examples/retryinterval/main.go
index 061ea09..54c1bce 100644
--- a/examples/retryinterval/main.go
+++ b/examples/retryinterval/main.go
@@ -13,8 +13,14 @@ func main() {
// RetryInterval sets a custom retry interval function for a request.
// Example: custom retry interval
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.RetryInterval(func(_ *req.Response, attempt int) time.Duration {
+ // Apply to all requests
+ c := httpx.New(httpx.RetryInterval(func(_ *req.Response, attempt int) time.Duration {
+ return time.Duration(attempt) * 100 * time.Millisecond
+ }))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryInterval(func(_ *req.Response, attempt int) time.Duration {
return time.Duration(attempt) * 100 * time.Millisecond
}))
}
diff --git a/examples/timeout/main.go b/examples/timeout/main.go
index db1fc80..68cd57e 100644
--- a/examples/timeout/main.go
+++ b/examples/timeout/main.go
@@ -11,7 +11,11 @@ import (
func main() {
// Timeout sets a per-request timeout using context cancellation.
- // Example: per-request timeout
- c := httpx.New()
- _ = httpx.Get[string](c, "https://example.com", httpx.Timeout(2*time.Second))
+ // Example: timeout
+ // Apply to all requests
+ c := httpx.New(httpx.Timeout(2 * time.Second))
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.Timeout(2*time.Second))
}
diff --git a/examples/useragent/main.go b/examples/useragent/main.go
index 7c0fafc..bccacfb 100644
--- a/examples/useragent/main.go
+++ b/examples/useragent/main.go
@@ -9,6 +9,10 @@ func main() {
// UserAgent sets the User-Agent header on a request or client.
// Example: set a User-Agent
+ // Apply to all requests
c := httpx.New(httpx.UserAgent("my-app/1.0"))
- _ = httpx.Get[string](c, "https://example.com")
+ httpx.Get[string](c, "https://example.com")
+
+ // Apply to a single request
+ httpx.Get[string](httpx.Default(), "https://example.com", httpx.UserAgent("my-app/1.0"))
}
diff --git a/options_auth.go b/options_auth.go
index fc1fc0b..e789509 100644
--- a/options_auth.go
+++ b/options_auth.go
@@ -12,8 +12,12 @@ import (
//
// Example: custom auth scheme
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.Auth("Token", "abc123"))
+// // Apply to all requests
+// c := httpx.New(httpx.Auth("Token", "abc123"))
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.Auth("Token", "abc123"))
func Auth(scheme, token string) OptionBuilder {
return OptionBuilder{}.Auth(scheme, token)
}
@@ -36,8 +40,12 @@ func (b OptionBuilder) Auth(scheme, token string) OptionBuilder {
//
// Example: bearer auth
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.Bearer("token"))
+// // Apply to all requests
+// c := httpx.New(httpx.Bearer("token"))
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.Bearer("token"))
func Bearer(token string) OptionBuilder {
return OptionBuilder{}.Bearer(token)
}
@@ -60,8 +68,12 @@ func (b OptionBuilder) Bearer(token string) OptionBuilder {
//
// Example: basic auth
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.Basic("user", "pass"))
+// // Apply to all requests
+// c := httpx.New(httpx.Basic("user", "pass"))
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.Basic("user", "pass"))
func Basic(user, pass string) OptionBuilder {
return OptionBuilder{}.Basic(user, pass)
}
diff --git a/options_request.go b/options_request.go
index 5566c26..9bd40d9 100644
--- a/options_request.go
+++ b/options_request.go
@@ -15,8 +15,12 @@ import (
// Applies to both client defaults and request-time headers.
// Example: apply a header
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.Header("X-Trace", "1"))
+// // Apply to all requests
+// c := httpx.New(httpx.Header("X-Trace", "1"))
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.Header("X-Trace", "1"))
func Header(key, value string) OptionBuilder {
return OptionBuilder{}.Header(key, value)
}
@@ -38,8 +42,15 @@ func (b OptionBuilder) Header(key, value string) OptionBuilder {
// Applies to both client defaults and request-time headers.
// Example: apply headers
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.Headers(map[string]string{
+// // Apply to all requests
+// c := httpx.New(httpx.Headers(map[string]string{
+// "X-Trace": "1",
+// "Accept": "application/json",
+// }))
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.Headers(map[string]string{
// "X-Trace": "1",
// "Accept": "application/json",
// }))
@@ -64,8 +75,12 @@ func (b OptionBuilder) Headers(values map[string]string) OptionBuilder {
// Applies to both client defaults and request-time headers.
// Example: set a User-Agent
//
+// // Apply to all requests
// c := httpx.New(httpx.UserAgent("my-app/1.0"))
-// _ = httpx.Get[string](c, "https://example.com")
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.UserAgent("my-app/1.0"))
func UserAgent(value string) OptionBuilder {
return OptionBuilder{}.UserAgent(value)
}
@@ -244,10 +259,14 @@ func (b OptionBuilder) Form(values map[string]string) OptionBuilder {
// @group Request Control
//
// Applies to both client defaults (via WithTimeout) and individual requests.
-// Example: per-request timeout
+// Example: timeout
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.Timeout(2*time.Second))
+// // Apply to all requests
+// c := httpx.New(httpx.Timeout(2 * time.Second))
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.Timeout(2*time.Second))
func Timeout(d time.Duration) OptionBuilder {
return OptionBuilder{}.Timeout(d)
}
diff --git a/options_retry.go b/options_retry.go
index 86091a2..b4f0b75 100644
--- a/options_retry.go
+++ b/options_retry.go
@@ -10,10 +10,14 @@ import (
// @group Retry
//
// Applies to both client defaults and individual requests.
-// Example: request retry count
+// Example: retry count
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.RetryCount(2))
+// // Apply to all requests
+// c := httpx.New(httpx.RetryCount(2))
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryCount(2))
func RetryCount(count int) OptionBuilder {
return OptionBuilder{}.RetryCount(count)
}
@@ -33,10 +37,14 @@ func (b OptionBuilder) RetryCount(count int) OptionBuilder {
// @group Retry
//
// Applies to both client defaults and individual requests.
-// Example: request retry interval
+// Example: retry interval
+//
+// // Apply to all requests
+// c := httpx.New(httpx.RetryFixedInterval(200 * time.Millisecond))
+// httpx.Get[string](c, "https://example.com")
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.RetryFixedInterval(200*time.Millisecond))
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryFixedInterval(200*time.Millisecond))
func RetryFixedInterval(interval time.Duration) OptionBuilder {
return OptionBuilder{}.RetryFixedInterval(interval)
}
@@ -56,10 +64,14 @@ func (b OptionBuilder) RetryFixedInterval(interval time.Duration) OptionBuilder
// @group Retry
//
// Applies to both client defaults and individual requests.
-// Example: request retry backoff
+// Example: retry backoff
+//
+// // Apply to all requests
+// c := httpx.New(httpx.RetryBackoff(100*time.Millisecond, 2*time.Second))
+// httpx.Get[string](c, "https://example.com")
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.RetryBackoff(100*time.Millisecond, 2*time.Second))
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryBackoff(100*time.Millisecond, 2*time.Second))
func RetryBackoff(min, max time.Duration) OptionBuilder {
return OptionBuilder{}.RetryBackoff(min, max)
}
@@ -81,8 +93,14 @@ func (b OptionBuilder) RetryBackoff(min, max time.Duration) OptionBuilder {
// Applies to both client defaults and individual requests.
// Example: custom retry interval
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.RetryInterval(func(_ *req.Response, attempt int) time.Duration {
+// // Apply to all requests
+// c := httpx.New(httpx.RetryInterval(func(_ *req.Response, attempt int) time.Duration {
+// return time.Duration(attempt) * 100 * time.Millisecond
+// }))
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryInterval(func(_ *req.Response, attempt int) time.Duration {
// return time.Duration(attempt) * 100 * time.Millisecond
// }))
func RetryInterval(fn req.GetRetryIntervalFunc) OptionBuilder {
@@ -106,8 +124,14 @@ func (b OptionBuilder) RetryInterval(fn req.GetRetryIntervalFunc) OptionBuilder
// Applies to both client defaults and individual requests.
// Example: retry on 503
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.RetryCondition(func(resp *req.Response, _ error) bool {
+// // Apply to all requests
+// c := httpx.New(httpx.RetryCondition(func(resp *req.Response, _ error) bool {
+// return resp != nil && resp.StatusCode == 503
+// }))
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryCondition(func(resp *req.Response, _ error) bool {
// return resp != nil && resp.StatusCode == 503
// }))
func RetryCondition(condition req.RetryConditionFunc) OptionBuilder {
@@ -131,8 +155,12 @@ func (b OptionBuilder) RetryCondition(condition req.RetryConditionFunc) OptionBu
// Applies to both client defaults and individual requests.
// Example: hook on retry
//
-// c := httpx.New()
-// _ = httpx.Get[string](c, "https://example.com", httpx.RetryHook(func(_ *req.Response, _ error) {}))
+// // Apply to all requests
+// c := httpx.New(httpx.RetryHook(func(_ *req.Response, _ error) {}))
+// httpx.Get[string](c, "https://example.com")
+//
+// // Apply to a single request
+// httpx.Get[string](httpx.Default(), "https://example.com", httpx.RetryHook(func(_ *req.Response, _ error) {}))
func RetryHook(hook req.RetryHookFunc) OptionBuilder {
return OptionBuilder{}.RetryHook(hook)
}
From 0c23851d0f69168a37779409958c372974d06ee6 Mon Sep 17 00:00:00 2001
From: Chris Miles
Date: Sun, 28 Dec 2025 21:21:16 -0600
Subject: [PATCH 5/5] docs: example refinement
---
README.md | 28 +++++++++++++++++++---------
client.go | 26 ++++++++++++++++----------
examples/delete/main.go | 2 +-
examples/deletectx/main.go | 2 +-
examples/get/main.go | 7 ++++++-
examples/getctx/main.go | 2 +-
examples/patch/main.go | 2 +-
examples/patchctx/main.go | 2 +-
examples/post/main.go | 2 +-
examples/postctx/main.go | 2 +-
examples/put/main.go | 2 +-
examples/putctx/main.go | 2 +-
12 files changed, 50 insertions(+), 29 deletions(-)
diff --git a/README.md b/README.md
index 7e4873e..ca14916 100644
--- a/README.md
+++ b/README.md
@@ -670,13 +670,15 @@ type DeleteResponse struct {
c := httpx.New()
res := httpx.Delete[DeleteResponse](c, "https://api.example.com/users/1")
-_, _ = res.Body, res.Err
+_, _ = res.Body, res.Err // Body is DeleteResponse
```
### Get
Get issues a GET request using the provided client.
+_Example: fetch GitHub pull requests (typed)_
+
```go
type PullRequest struct {
Number int `json:"number"`
@@ -691,6 +693,14 @@ if res.Err != nil {
godump.Dump(res.Body)
```
+_Example: bind to a string body_
+
+```go
+c2 := httpx.New()
+res2 := httpx.Get[string](c2, "https://httpbin.org/uuid")
+_, _ = res2.Body, res2.Err // Body is string
+```
+
### Head
Head issues a HEAD request using the provided client.
@@ -725,7 +735,7 @@ type User struct {
c := httpx.New()
res := httpx.Patch[UpdateUser, User](c, "https://api.example.com/users/1", UpdateUser{Name: "Ana"})
-_, _ = res.Body, res.Err
+_, _ = res.Body, res.Err // Body is User
```
### Post
@@ -742,7 +752,7 @@ type User struct {
c := httpx.New()
res := httpx.Post[CreateUser, User](c, "https://api.example.com/users", CreateUser{Name: "Ana"})
-_, _ = res.Body, res.Err
+_, _ = res.Body, res.Err // Body is User
```
### Put
@@ -759,7 +769,7 @@ type User struct {
c := httpx.New()
res := httpx.Put[UpdateUser, User](c, "https://api.example.com/users/1", UpdateUser{Name: "Ana"})
-_, _ = res.Body, res.Err
+_, _ = res.Body, res.Err // Body is User
```
## Requests (Context)
@@ -776,7 +786,7 @@ type DeleteResponse struct {
c := httpx.New()
ctx := context.Background()
res := httpx.DeleteCtx[DeleteResponse](c, ctx, "https://api.example.com/users/1")
-_, _ = res.Body, res.Err
+_, _ = res.Body, res.Err // Body is DeleteResponse
```
### GetCtx
@@ -791,7 +801,7 @@ type User struct {
c := httpx.New()
ctx := context.Background()
res := httpx.GetCtx[User](c, ctx, "https://api.example.com/users/1")
-_, _ = res.Body, res.Err
+_, _ = res.Body, res.Err // Body is User
```
### HeadCtx
@@ -831,7 +841,7 @@ type User struct {
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
+_, _ = res.Body, res.Err // Body is User
```
### PostCtx
@@ -849,7 +859,7 @@ type User struct {
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
+_, _ = res.Body, res.Err // Body is User
```
### PutCtx
@@ -867,7 +877,7 @@ type User struct {
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
+_, _ = res.Body, res.Err // Body is User
```
## Retry
diff --git a/client.go b/client.go
index 278a657..7a1c96f 100644
--- a/client.go
+++ b/client.go
@@ -126,7 +126,7 @@ func (c *Client) Raw() *req.Client {
// Get issues a GET request using the provided client.
// @group Requests
//
-// Example: fetch GitHub pull requests
+// Example: fetch GitHub pull requests (typed)
//
// type PullRequest struct {
// Number int `json:"number"`
@@ -139,6 +139,12 @@ func (c *Client) Raw() *req.Client {
// return
// }
// godump.Dump(res.Body)
+//
+// Example: bind to a string body
+//
+// c2 := httpx.New()
+// res2 := httpx.Get[string](c2, "https://httpbin.org/uuid")
+// _, _ = res2.Body, res2.Err // Body is string
func Get[T any](client *Client, url string, opts ...Option) Result[T] {
return do[T](client, nil, methodGet, url, nil, opts)
}
@@ -157,7 +163,7 @@ func Get[T any](client *Client, url string, opts ...Option) Result[T] {
//
// c := httpx.New()
// res := httpx.Post[CreateUser, User](c, "https://api.example.com/users", CreateUser{Name: "Ana"})
-// _, _ = res.Body, res.Err
+// _, _ = res.Body, res.Err // Body is User
func Post[In any, Out any](client *Client, url string, body In, opts ...Option) Result[Out] {
return do[Out](client, nil, methodPost, url, body, opts)
}
@@ -176,7 +182,7 @@ func Post[In any, Out any](client *Client, url string, body In, opts ...Option)
//
// c := httpx.New()
// res := httpx.Put[UpdateUser, User](c, "https://api.example.com/users/1", UpdateUser{Name: "Ana"})
-// _, _ = res.Body, res.Err
+// _, _ = res.Body, res.Err // Body is User
func Put[In any, Out any](client *Client, url string, body In, opts ...Option) Result[Out] {
return do[Out](client, nil, methodPut, url, body, opts)
}
@@ -195,7 +201,7 @@ func Put[In any, Out any](client *Client, url string, body In, opts ...Option) R
//
// c := httpx.New()
// res := httpx.Patch[UpdateUser, User](c, "https://api.example.com/users/1", UpdateUser{Name: "Ana"})
-// _, _ = res.Body, res.Err
+// _, _ = res.Body, res.Err // Body is User
func Patch[In any, Out any](client *Client, url string, body In, opts ...Option) Result[Out] {
return do[Out](client, nil, methodPatch, url, body, opts)
}
@@ -211,7 +217,7 @@ func Patch[In any, Out any](client *Client, url string, body In, opts ...Option)
//
// c := httpx.New()
// res := httpx.Delete[DeleteResponse](c, "https://api.example.com/users/1")
-// _, _ = res.Body, res.Err
+// _, _ = res.Body, res.Err // Body is DeleteResponse
func Delete[T any](client *Client, url string, opts ...Option) Result[T] {
return do[T](client, nil, methodDelete, url, nil, opts)
}
@@ -252,7 +258,7 @@ func Options[T any](client *Client, url string, opts ...Option) Result[T] {
// c := httpx.New()
// ctx := context.Background()
// res := httpx.GetCtx[User](c, ctx, "https://api.example.com/users/1")
-// _, _ = res.Body, res.Err
+// _, _ = res.Body, res.Err // Body is User
func GetCtx[T any](client *Client, ctx context.Context, url string, opts ...Option) Result[T] {
return do[T](client, ctx, methodGet, url, nil, opts)
}
@@ -272,7 +278,7 @@ func GetCtx[T any](client *Client, ctx context.Context, url string, opts ...Opti
// 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
+// _, _ = res.Body, res.Err // Body is User
func PostCtx[In any, Out any](client *Client, ctx context.Context, url string, body In, opts ...Option) Result[Out] {
return do[Out](client, ctx, methodPost, url, body, opts)
}
@@ -292,7 +298,7 @@ func PostCtx[In any, Out any](client *Client, ctx context.Context, url string, b
// 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
+// _, _ = res.Body, res.Err // Body is User
func PutCtx[In any, Out any](client *Client, ctx context.Context, url string, body In, opts ...Option) Result[Out] {
return do[Out](client, ctx, methodPut, url, body, opts)
}
@@ -312,7 +318,7 @@ func PutCtx[In any, Out any](client *Client, ctx context.Context, url string, bo
// 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
+// _, _ = res.Body, res.Err // Body is User
func PatchCtx[In any, Out any](client *Client, ctx context.Context, url string, body In, opts ...Option) Result[Out] {
return do[Out](client, ctx, methodPatch, url, body, opts)
}
@@ -329,7 +335,7 @@ func PatchCtx[In any, Out any](client *Client, ctx context.Context, url string,
// c := httpx.New()
// ctx := context.Background()
// res := httpx.DeleteCtx[DeleteResponse](c, ctx, "https://api.example.com/users/1")
-// _, _ = res.Body, res.Err
+// _, _ = res.Body, res.Err // Body is DeleteResponse
func DeleteCtx[T any](client *Client, ctx context.Context, url string, opts ...Option) Result[T] {
return do[T](client, ctx, methodDelete, url, nil, opts)
}
diff --git a/examples/delete/main.go b/examples/delete/main.go
index e8b8b2f..b329f87 100644
--- a/examples/delete/main.go
+++ b/examples/delete/main.go
@@ -15,5 +15,5 @@ func main() {
c := httpx.New()
res := httpx.Delete[DeleteResponse](c, "https://api.example.com/users/1")
- _, _ = res.Body, res.Err
+ _, _ = res.Body, res.Err // Body is DeleteResponse
}
diff --git a/examples/deletectx/main.go b/examples/deletectx/main.go
index 105e0ba..16569f8 100644
--- a/examples/deletectx/main.go
+++ b/examples/deletectx/main.go
@@ -19,5 +19,5 @@ func main() {
c := httpx.New()
ctx := context.Background()
res := httpx.DeleteCtx[DeleteResponse](c, ctx, "https://api.example.com/users/1")
- _, _ = res.Body, res.Err
+ _, _ = res.Body, res.Err // Body is DeleteResponse
}
diff --git a/examples/get/main.go b/examples/get/main.go
index 9610dc6..8c7b5fc 100644
--- a/examples/get/main.go
+++ b/examples/get/main.go
@@ -11,7 +11,7 @@ import (
func main() {
// Get issues a GET request using the provided client.
- // Example: fetch GitHub pull requests
+ // Example: fetch GitHub pull requests (typed)
type PullRequest struct {
Number int `json:"number"`
Title string `json:"title"`
@@ -23,4 +23,9 @@ func main() {
return
}
godump.Dump(res.Body)
+
+ // Example: bind to a string body
+ c2 := httpx.New()
+ res2 := httpx.Get[string](c2, "https://httpbin.org/uuid")
+ _, _ = res2.Body, res2.Err // Body is string
}
diff --git a/examples/getctx/main.go b/examples/getctx/main.go
index faecc1c..c5bdcda 100644
--- a/examples/getctx/main.go
+++ b/examples/getctx/main.go
@@ -19,5 +19,5 @@ func main() {
c := httpx.New()
ctx := context.Background()
res := httpx.GetCtx[User](c, ctx, "https://api.example.com/users/1")
- _, _ = res.Body, res.Err
+ _, _ = res.Body, res.Err // Body is User
}
diff --git a/examples/patch/main.go b/examples/patch/main.go
index 7ccec2a..4c22c44 100644
--- a/examples/patch/main.go
+++ b/examples/patch/main.go
@@ -18,5 +18,5 @@ func main() {
c := httpx.New()
res := httpx.Patch[UpdateUser, User](c, "https://api.example.com/users/1", UpdateUser{Name: "Ana"})
- _, _ = res.Body, res.Err
+ _, _ = res.Body, res.Err // Body is User
}
diff --git a/examples/patchctx/main.go b/examples/patchctx/main.go
index 6783c02..c59fb7a 100644
--- a/examples/patchctx/main.go
+++ b/examples/patchctx/main.go
@@ -22,5 +22,5 @@ func main() {
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
+ _, _ = res.Body, res.Err // Body is User
}
diff --git a/examples/post/main.go b/examples/post/main.go
index 13d08d8..5ed3892 100644
--- a/examples/post/main.go
+++ b/examples/post/main.go
@@ -18,5 +18,5 @@ func main() {
c := httpx.New()
res := httpx.Post[CreateUser, User](c, "https://api.example.com/users", CreateUser{Name: "Ana"})
- _, _ = res.Body, res.Err
+ _, _ = res.Body, res.Err // Body is User
}
diff --git a/examples/postctx/main.go b/examples/postctx/main.go
index 0655d80..c6d1864 100644
--- a/examples/postctx/main.go
+++ b/examples/postctx/main.go
@@ -22,5 +22,5 @@ func main() {
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
+ _, _ = res.Body, res.Err // Body is User
}
diff --git a/examples/put/main.go b/examples/put/main.go
index c85ec6c..3ef6f4f 100644
--- a/examples/put/main.go
+++ b/examples/put/main.go
@@ -18,5 +18,5 @@ func main() {
c := httpx.New()
res := httpx.Put[UpdateUser, User](c, "https://api.example.com/users/1", UpdateUser{Name: "Ana"})
- _, _ = res.Body, res.Err
+ _, _ = res.Body, res.Err // Body is User
}
diff --git a/examples/putctx/main.go b/examples/putctx/main.go
index e14772e..84fa4e2 100644
--- a/examples/putctx/main.go
+++ b/examples/putctx/main.go
@@ -22,5 +22,5 @@ func main() {
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
+ _, _ = res.Body, res.Err // Body is User
}