Request Options
Request options are functional configuration items passed to request methods via the RequestOption type, enabling fine-grained request control.
result, err := client.Post(url,
httpc.WithJSON(data),
httpc.WithBearerToken(token),
httpc.WithQuery("page", 1),
)All options can be freely combined and are applied in the order they are passed.
Options Overview
| Group | Options |
|---|---|
| Headers | WithHeader, WithHeaderMap, WithUserAgent |
| Authentication | WithBasicAuth, WithBearerToken |
| Request Body | WithJSON, WithXML, WithForm, WithFormData, WithFile, WithBinary, WithBody |
| Query Parameters | WithQuery, WithQueryMap |
| Cookies | WithCookies, WithCookieMap, WithCookieString, WithSecureCookie |
| Request Control | WithContext, WithTimeout, WithNoTimeout, WithMaxRetries, WithRetryNonIdempotent, WithFollowRedirects, WithMaxRedirects, WithAllowPrivateIPs, WithStreamBody |
| Callbacks | WithOnRequest, WithOnResponse |
Some options override same-named defaults in the client configuration (Config):
| Option | Config field overridden (default) |
|---|---|
WithUserAgent | Defaults.UserAgent ("httpc/1.0") |
WithHeader / WithHeaderMap | Same-named default headers in Defaults.Headers |
WithTimeout | Timeouts.Request (180s) |
WithNoTimeout | Timeouts.Request (lifts the default ceiling) |
WithMaxRetries | Retry.MaxRetries (3) |
WithRetryNonIdempotent | Retry.RetryNonIdempotent (false) |
WithFollowRedirects | Defaults.FollowRedirects (true) |
WithMaxRedirects | Defaults.MaxRedirects (10) |
WithAllowPrivateIPs | Security.AllowPrivateIPs (false) |
TIP
nil options are silently skipped instead of raising an error — handy for conditionally assembling option slices. Any option that returns an error aborts the request (wrapped uniformly as failed to apply request option).
Headers
WithHeader
func WithHeader(key, value string) RequestOptionSets a single request header. Keys and values are security-validated (CRLF injection protection).
result, err := client.Get(url,
httpc.WithHeader("X-Custom", "value"),
)WithHeaderMap
func WithHeaderMap(headers map[string]string) RequestOptionSets multiple request headers at once.
result, err := client.Get(url,
httpc.WithHeaderMap(map[string]string{
"Accept": "application/json",
"X-Request-ID": "abc123",
}),
)WithUserAgent
func WithUserAgent(userAgent string) RequestOptionSets the User-Agent header. This is a convenience wrapper for WithHeader("User-Agent", ...).
Authentication
WithBasicAuth
func WithBasicAuth(username, password string) RequestOptionSets HTTP Basic authentication. The username cannot be empty and credential length is limited.
result, err := client.Get(url,
httpc.WithBasicAuth("admin", "password"),
)WithBearerToken
func WithBearerToken(token string) RequestOptionSets the Authorization: Bearer <token> header. The token cannot be empty.
result, err := client.Get(url,
httpc.WithBearerToken("eyJhbGciOiJIUzI1NiIs..."),
)Request Body
WithJSON
func WithJSON(data any) RequestOptionSets a JSON request body, automatically adding Content-Type: application/json.
result, err := client.Post(url,
httpc.WithJSON(map[string]any{
"name": "test",
"email": "[email protected]",
}),
)WithXML
func WithXML(data any) RequestOptionSets an XML request body, automatically adding Content-Type: application/xml.
WithForm
func WithForm(data map[string]string) RequestOptionSets a URL-encoded form request body, automatically adding Content-Type: application/x-www-form-urlencoded.
result, err := client.Post(url,
httpc.WithForm(map[string]string{
"username": "admin",
"password": "secret",
}),
)WithFormData
func WithFormData(data *FormData) RequestOptionSets a multipart/form-data request body, supporting mixed file and field uploads.
result, err := client.Post(url,
httpc.WithFormData(&httpc.FormData{
Fields: map[string]string{"description": "upload"},
Files: map[string]*httpc.FileData{
"file": {Filename: "doc.pdf", Content: fileBytes},
},
}),
)WithFile
func WithFile(fieldName, filename string, content []byte) RequestOptionConvenient file upload. Automatically builds a multipart request body. The filename is processed for path-traversal protection.
result, err := client.Post(url,
httpc.WithFile("upload", "report.csv", csvBytes),
)WithBinary
func WithBinary(data []byte, contentType ...string) RequestOptionSets a binary request body. The default Content-Type is application/octet-stream, customizable.
result, err := client.Post(url,
httpc.WithBinary(imageBytes, "image/png"),
)WithBody
func WithBody(data any, kind ...BodyKind) RequestOptionGeneric request-body setter, supporting auto-detection and explicit type specification.
Auto-detection rules (default BodyAuto):
| Input Type | Content-Type |
|---|---|
string | text/plain; charset=utf-8 |
[]byte | application/octet-stream |
map[string]string | application/x-www-form-urlencoded |
*FormData | multipart/form-data |
io.Reader | Not set (handled by the caller) |
| Other types | application/json |
Explicit type specification:
// Auto-detect (default)
result, _ := client.Post(url, httpc.WithBody(data))
// Force JSON
result, _ := client.Post(url, httpc.WithBody(data, httpc.BodyJSON))
// Force XML
result, _ := client.Post(url, httpc.WithBody(data, httpc.BodyXML))| Constant | Meaning |
|---|---|
BodyAuto | Auto-detect (default) |
BodyJSON | Force JSON |
BodyXML | Force XML |
BodyForm | Force form |
BodyBinary | Force binary |
BodyMultipart | Force multipart (requires *FormData) |
Input constraints for explicit types:
| Type | Input requirement |
|---|---|
BodyJSON / BodyXML | Any non-nil data |
BodyForm | map[string]string or url.Values (validated per field) |
BodyBinary | []byte or string, non-empty |
BodyMultipart | *FormData |
A type mismatch (e.g., passing a non-*FormData to BodyMultipart) or a nil data returns an error.
io.Reader bypasses size validation
io.Reader request bodies bypass request-body size validation. When reading from an untrusted source, wrap it with io.LimitReader to prevent resource exhaustion:
limited := io.LimitReader(untrustedReader, 10<<20) // cap at 10 MBQuery Parameters
WithQuery
func WithQuery(key string, value any) RequestOptionSets a single query parameter.
result, err := client.Get(url,
httpc.WithQuery("page", 1),
httpc.WithQuery("limit", 10),
)WithQueryMap
func WithQueryMap(params map[string]any) RequestOptionSets multiple query parameters at once.
result, err := client.Get(url,
httpc.WithQueryMap(map[string]any{
"page": 1,
"limit": 10,
"sort": "created_at",
}),
)Cookies
WithCookies
func WithCookies(cookies []http.Cookie) RequestOptionAdds one or more cookies, each security-validated: names ≤256 characters, values ≤4096 characters; control characters and illegal cookie characters are rejected; Domain (≤255) and Path (≤1024) are validated when set. The whole batch is pre-allocated and validated in a single pass.
// A single cookie: pass a one-element slice
result, err := client.Get(url,
httpc.WithCookies([]http.Cookie{{Name: "session", Value: "abc123"}}),
)
// Multiple cookies
cookies := []http.Cookie{
{Name: "session_id", Value: "abc123"},
{Name: "user_pref", Value: "dark_mode"},
{Name: "lang", Value: "en"},
}
result, err = client.Get("https://api.example.com",
httpc.WithCookies(cookies),
)WithCookieMap
func WithCookieMap(cookies map[string]string) RequestOptionAdds simple cookies in bulk. Suitable for scenarios requiring only name-value pairs.
result, err := client.Get(url,
httpc.WithCookieMap(map[string]string{
"session_id": "abc123",
"lang": "en",
}),
)WithCookieString
func WithCookieString(cookieString string) RequestOptionAdds cookies from a raw Cookie header string.
result, err := client.Get(url,
httpc.WithCookieString("session=abc123; lang=en"),
)WithSecureCookie
func WithSecureCookie(securityConfig *CookieSecurityConfig) RequestOptionEnforces validation of the security attributes (Secure, HttpOnly, SameSite) of request cookies.
WARNING
This option only validates cookies that already exist at the time it is applied. You must place WithSecureCookie after all WithCookies/WithCookieMap/WithCookieString calls; otherwise cookies added later will not be validated. For session-level cookie-security validation that is not subject to ordering, use SessionManager.SetCookieSecurity.
// Correct order: add cookies first, then validate
result, err := client.Get(url,
httpc.WithCookies(sessionCookies),
httpc.WithCookieMap(otherCookies),
httpc.WithSecureCookie(httpc.StrictCookieSecurityConfig()),
)Request Control
WithContext
func WithContext(ctx context.Context) RequestOptionSets the request context, supporting timeout and cancellation. The context cannot be nil.
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
result, err := client.Get(url, httpc.WithContext(ctx))WithTimeout
func WithTimeout(timeout time.Duration) RequestOptionSets a per-request timeout, overriding the client default. Range: 0 to 30 minutes.
result, err := client.Get(url, httpc.WithTimeout(5*time.Second))WithNoTimeout
func WithNoTimeout() RequestOptionLifts the client-level default request timeout (Config.Timeouts.Request, default 180s) for this single request, letting a slow call run for as long as the server takes. Only the client default is lifted: an explicit WithTimeout on the same request takes precedence, and any deadline on the caller-provided context (WithContext or the ctx parameter) is always honored. Dial/TLS/response-header timeouts are unaffected.
// Lift the default 180s ceiling for long calls (large uploads, slow reports)
result, err := client.Post(uploadURL,
httpc.WithFile("file", "backup.tar.gz", data),
httpc.WithNoTimeout(),
)WithMaxRetries
func WithMaxRetries(maxRetries int) RequestOptionSets the per-request maximum retry count, overriding the client configuration. Range: 0-10.
result, err := client.Get(url, httpc.WithMaxRetries(3))WithRetryNonIdempotent
func WithRetryNonIdempotent(allow bool) RequestOptionOverrides, for this single request, whether non-idempotent methods (POST, PATCH, and custom methods) may be retried, in both directions over the client-level Config.Retry.RetryNonIdempotent (default false): true retries a POST on a client that otherwise forbids it; false pins a single attempt on a client that allows it. Idempotent methods (GET/HEAD, etc.) are unaffected, and the WithMaxRetries cap still applies.
WARNING
Enabling retries for a non-idempotent request means a timeout or retryable 5xx may send the request body more than once (duplicate orders, duplicate payments). Use it only against endpoints that tolerate replay, or guard them with an idempotency key.
// The client forbids POST retries by default; opt in for this call (endpoint is replay-safe via idempotency key)
result, err := client.Post(orderURL,
httpc.WithJSON(order),
httpc.WithMaxRetries(3),
httpc.WithRetryNonIdempotent(true),
)WithFollowRedirects
func WithFollowRedirects(follow bool) RequestOptionControls whether to follow redirects.
// Disable following redirects
result, err := client.Get(url, httpc.WithFollowRedirects(false))WithMaxRedirects
func WithMaxRedirects(maxRedirects int) RequestOptionSets the per-request maximum redirect count. Range: 0-50.
WARNING
0 does not disable redirects. The engine treats 0 as an "unset" sentinel and falls back to the default cap (10), so WithMaxRedirects(0) is equivalent to omitting the option. To fully disable redirect following, use WithFollowRedirects(false) instead.
WithAllowPrivateIPs
func WithAllowPrivateIPs(allow bool) RequestOptionOverrides the client's SSRF policy for a single request. When allow is true, the request may access localhost and private/reserved IP ranges (127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 169.254.0.0/16, etc.) and follow redirects to such addresses; when false, SSRF protection is enforced for this request even if the client is configured with Security.AllowPrivateIPs=true.
WARNING
This is a per-request escape hatch from SSRF protection, suited for cases where a default-secure client (AllowPrivateIPs=false) occasionally needs to reach internal services, loopback addresses, or a local dev server.
Enable it only when the request URL is trusted and not derived from untrusted user input. To allow internal access for an entire client, set Security.AllowPrivateIPs=true on Config directly.
// The default client blocks private IPs; this call allows it per request
result, err := httpc.Get("http://localhost:8080/health",
httpc.WithAllowPrivateIPs(true),
)WithStreamBody
func WithStreamBody(stream bool) RequestOptionEnables streaming mode; the response body is not cached in memory.
WARNING
Streaming mode only takes effect via Download. When used with the standard request methods (Get/Post/Put/Patch/Delete/Head/Options/Request), the response body is read in full and converted into a Result, after which the underlying stream is closed — the returned Result body is empty and the caller cannot consume the stream.
To actually stream-download large files without caching them in memory, use Download.
Callbacks
WithOnRequest
func WithOnRequest(callback func(req RequestMutator) error) RequestOptionRegisters a pre-send callback. Multiple callbacks can be chained and execute in the order they are added. Returning an error aborts the request.
result, err := client.Get(url,
httpc.WithOnRequest(func(req httpc.RequestMutator) error {
log.Printf("Sending %s %s", req.Method(), req.URL())
return nil
}),
)WithOnResponse
func WithOnResponse(callback func(resp ResponseMutator) error) RequestOptionRegisters a post-receive callback. Multiple callbacks can be chained and execute in the order they are added.
result, err := client.Get(url,
httpc.WithOnResponse(func(resp httpc.ResponseMutator) error {
log.Printf("Received response: %d %s", resp.StatusCode(), resp.Status())
return nil
}),
)See Also
- Constants and Types - BodyKind constants and type aliases
- Interface Definitions - RequestMutator, ResponseMutator interfaces
- Request and Response - Request options usage guide