Documentation
¶
Overview ¶
Package reqs is requests-style HTTP for Go.
reqs wraps net/http with a clean API inspired by Python's requests library: context.Context first, io.Reader bodies, http.Header for headers, *http.Cookie for cookies, errors via errors.Is and errors.As.
Quick start:
resp, err := reqs.Get(ctx, "https://api.example.com/users")
if err != nil {
return err
}
var users []User
if err := resp.JSON(&users); err != nil {
return err
}
All optional knobs go in one struct, Opts. Pass zero or one:
resp, err := reqs.Post(ctx, url, reqs.Opts{
JSON: payload,
Header: http.Header{"X-Custom": {"value"}},
Auth: reqs.BasicAuth("user", "pass"),
})
Use *Client to share cookies, headers, auth, and the connection pool across many requests:
c := reqs.New()
c.Header.Set("X-API-Key", apiKey)
resp, err := c.Get(ctx, url)
Index ¶
- Constants
- Variables
- func CookiesAsMap(cs []*http.Cookie) map[string]string
- func CookiesFromMap(m map[string]string) []*http.Cookie
- type Auth
- type ChallengeAuth
- type Client
- func (c *Client) Close() error
- func (c *Client) Delete(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func (c *Client) Do(ctx context.Context, req *http.Request) (*Response, error)
- func (c *Client) Get(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func (c *Client) Head(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func (c *Client) Options(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func (c *Client) Patch(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func (c *Client) Post(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func (c *Client) Put(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func (c *Client) Request(ctx context.Context, method, url string, opts ...Opts) (*Response, error)
- type CookieJar
- type File
- type HTTPError
- type Link
- type Opts
- type RequestError
- type Response
- func Delete(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func Get(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func Head(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func Options(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func Patch(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func Post(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func Put(ctx context.Context, url string, opts ...Opts) (*Response, error)
- func Request(ctx context.Context, method, url string, opts ...Opts) (*Response, error)
- func (r *Response) ApparentEncoding() string
- func (r *Response) Bytes() ([]byte, error)
- func (r *Response) Encoding() string
- func (r *Response) JSON(v any) error
- func (r *Response) Links() map[string]Link
- func (r *Response) OK() bool
- func (r *Response) RaiseForStatus() error
- func (r *Response) SetEncoding(name string)
- func (r *Response) Text() (string, error)
- type URLError
Examples ¶
Constants ¶
const ( // Version is the library version. Version = "0.2.0" // UserAgent is the default User-Agent header sent with each request. UserAgent = "reqs/" + Version )
Variables ¶
var ( // ErrTimeout is returned when a request exceeds its deadline (connect // or read) or the parent context expires with a deadline. ErrTimeout = errors.New("reqs: timeout") // ErrCanceled is returned when a request is canceled via its context // without a deadline. ErrCanceled = errors.New("reqs: canceled") // ErrConnect is returned for transport-level connection failures // (dial errors, refused connections, broken pipes). ErrConnect = errors.New("reqs: connection error") // ErrTLS is returned for TLS handshake or certificate verification // failures. ErrTLS = errors.New("reqs: tls error") // ErrTooManyRedirects is returned when a redirect chain exceeds // (*Client).MaxRedirects. ErrTooManyRedirects = errors.New("reqs: too many redirects") // ErrInvalidURL is returned when a URL fails parsing or validation. ErrInvalidURL = errors.New("reqs: invalid url") // ErrInvalidScheme is returned when a URL scheme is not http or https // (and the request was not handed off to a custom transport). ErrInvalidScheme = errors.New("reqs: invalid scheme") // ErrMissingScheme is returned when a URL has no scheme (e.g. "example.com"). ErrMissingScheme = errors.New("reqs: missing scheme") // ErrInvalidHeader is returned when a header name or value contains // reserved or control characters. ErrInvalidHeader = errors.New("reqs: invalid header") // ErrInvalidProxy is returned when a configured proxy URL cannot be // parsed or has no host. ErrInvalidProxy = errors.New("reqs: invalid proxy url") // ErrUnrewindable is returned when a redirect requires resending the // request body but the body is not seekable. ErrUnrewindable = errors.New("reqs: unrewindable body") )
Sentinel errors. Errors returned by this package wrap one of these (where applicable) and can be checked with errors.Is.
var DefaultClient = &Client{TrustEnv: true}
DefaultClient is used by the package-level convenience functions (Get, Post, ...). It has no Jar by default, so cookies are not persisted across top-level calls — matching Python requests' module functions which create a fresh Session per call.
Functions ¶
func CookiesAsMap ¶
CookiesAsMap collapses a slice of cookies into a name→value map. When multiple cookies share a name (e.g., from different paths or domains) the last one wins. For domain/path-aware lookup, iterate the slice directly.
Types ¶
type Auth ¶
type Auth interface {
// Apply sets headers (or other state) on req before it is sent. Auth
// implementations must not consume or modify the request body.
Apply(req *http.Request) error
}
Auth attaches credentials to outgoing requests.
func BasicAuth ¶
BasicAuth attaches HTTP Basic authentication to each request.
Example ¶
ExampleBasicAuth attaches HTTP Basic credentials.
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(r.Header.Get("Authorization")))
}))
defer s.Close()
resp, _ := reqs.Get(context.Background(), s.URL,
reqs.Opts{Auth: reqs.BasicAuth("alice", "wonder")})
body, _ := resp.Bytes()
fmt.Print(string(body))
Output: Basic YWxpY2U6d29uZGVy
func DigestAuth ¶
DigestAuth attaches HTTP Digest authentication. Supported algorithms: MD5 (default), MD5-SESS, SHA, SHA-256, SHA-512. The first request goes out unauthenticated; on a 401 challenge the credentials are computed and the request is retried once. Subsequent requests reuse the challenge state (preemptive auth) until the server issues a new nonce.
Safe for concurrent use. State is per-DigestAuth instance.
type ChallengeAuth ¶
ChallengeAuth is implemented by auth schemes that need to inspect a 401 response (e.g. Digest). When the server returns 401, Client.Do calls Challenge once with the original request and 401 response, then retries the request a single time.
type Client ¶
type Client struct {
// Transport is the underlying http.RoundTripper. Nil means a tuned
// *http.Transport is initialized lazily and reused.
Transport http.RoundTripper
// Jar persists cookies across requests. Nil means cookies are not
// stored (per-request Cookies are still sent and Set-Cookie headers
// on responses are visible via Response.Cookies()).
Jar http.CookieJar
// Header is merged into every outgoing request below Opts.Header.
Header http.Header
// Auth is applied to every outgoing request unless Opts.Auth
// overrides it.
Auth Auth
// Timeout is the default per-request timeout. Zero means no timeout.
// Opts.Timeout overrides per request.
Timeout time.Duration
// Proxies maps scheme/host keys to proxy URLs. See selectProxy in
// proxy.go for the lookup rules.
Proxies map[string]string
// Verify controls TLS server certificate verification:
// - nil or bool true: use system CA bundle
// - bool false: skip verification (NOT for production)
// - string: path to a PEM file or directory of PEM files
Verify any
// Cert configures client-side certificates (mTLS):
// - string: path to a PEM file containing both cert and key
// - [2]string: {certPath, keyPath}
Cert any
// MaxRedirects is the redirect chain limit. Zero means 30 (the
// Python requests default).
MaxRedirects int
// TrustEnv enables NETRC, NO_PROXY, and *_PROXY environment lookups.
TrustEnv bool
// MaxResponseSize limits the number of bytes read by Response.Bytes
// (and therefore Text/JSON). Zero means no limit.
MaxResponseSize int64
// contains filtered or unexported fields
}
Client persists configuration and connection state across requests. It is the goreqs analogue of Python requests.Session.
The zero value is usable; New returns a Client with TrustEnv set and a fresh in-memory cookie jar (matching requests.Session behavior).
Use *Client to share cookies, default headers, auth, the connection pool, and TLS settings across many calls.
Example ¶
ExampleClient shows persistent state across requests.
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, r.Header.Get("X-API-Key"))
}))
defer s.Close()
c := reqs.New()
defer c.Close()
c.Header = http.Header{"X-API-Key": {"secret"}}
resp, _ := c.Get(context.Background(), s.URL)
body, _ := resp.Bytes()
fmt.Print(string(body))
Output: secret
func New ¶
func New() *Client
New returns a new Client with TrustEnv enabled and a fresh in-memory cookie jar.
func (*Client) Close ¶
Close releases idle connections held by the Client's transport. Safe to call multiple times. Calling Close does not invalidate the Client; subsequent requests will reopen connections.
func (*Client) Do ¶
Do sends a hand-built *http.Request through the Client's transport pipeline. This is the stdlib drop-down: minimal magic. Client.Header fills missing slots, Client.Auth applies if no Authorization is set, Client.Jar attaches and extracts cookies, Client.Timeout applies if the request's context has no deadline. URL and body are not touched.
func (*Client) Head ¶
Head sends a HEAD request. Redirects are NOT followed by default (matching Python). Override with Opts.AllowRedirects.
func (*Client) Post ¶
Post sends a POST request. The body, if any, comes from Opts.Body, Opts.JSON, Opts.Form, or Opts.Files (see Opts for precedence).
type File ¶
type File struct {
// Name is the multipart form field name. Required.
Name string
// Filename is the filename reported to the server. If empty, it is
// derived from the underlying *os.File (or falls back to Name).
Filename string
// File is the upload body. Required.
File io.Reader
// ContentType is the Content-Type for this part. If empty, the
// content type is inferred from the filename extension and falls
// back to application/octet-stream.
ContentType string
// Header optionally augments or overrides the default part headers
// (Content-Disposition, Content-Type).
Header textproto.MIMEHeader
}
File describes a single multipart upload field. It collapses Python requests' 2/3/4-tuple variants (filename / fileobj / content-type / custom-headers) into one struct.
type HTTPError ¶
type HTTPError struct {
Resp *Response
}
HTTPError is returned by (*Response).RaiseForStatus when StatusCode is in the 4xx or 5xx range.
type Opts ¶
type Opts struct {
// Header is merged into the request headers above any Client.Header
// defaults.
Header http.Header
// Params are appended to the URL's query string.
Params url.Values
// Cookies are added to the request via (*http.Request).AddCookie.
Cookies []*http.Cookie
// Body is a raw request body. Used as-is; no Content-Type is set
// automatically.
Body io.Reader
// JSON is marshaled with encoding/json and sent with
// Content-Type: application/json.
JSON any
// Form is sent application/x-www-form-urlencoded. When Files is
// also set, Form is included as text parts of the multipart body.
Form url.Values
// Files trigger multipart/form-data encoding.
Files []File
// Auth overrides Client.Auth for this request.
Auth Auth
// Timeout is a per-request timeout. Zero means use Client.Timeout
// (or no timeout). Implemented via context.WithTimeout in Client.do.
Timeout time.Duration
// AllowRedirects enables automatic redirect following. Nil uses the
// per-method default: true for GET/POST/PUT/PATCH/DELETE/OPTIONS,
// false for HEAD.
AllowRedirects *bool
// Stream, when true, leaves the response body unbuffered. The
// caller must read and close r.Body. When false (the default), the
// body is consumed into r.Bytes() before Client.do returns.
Stream bool
// Proxies overrides Client.Proxies for this request.
Proxies map[string]string
// Verify overrides Client.Verify for this request.
Verify any
// Cert overrides Client.Cert for this request.
Cert any
}
Opts is the bag of optional knobs for a single request. All fields are optional. Pass zero or one Opts value to a convenience function:
goreqs.Get(ctx, url) // no Opts
goreqs.Get(ctx, url, goreqs.Opts{Params: q}) // with Opts
goreqs.Post(ctx, url, goreqs.Opts{JSON: payload})
At most one of Body, JSON, Form, or Files may be set, with one exception: Files may coexist with Form (the Form fields are added as text parts in the multipart body). Conflicting bodies cause buildRequest to return an error.
type RequestError ¶
RequestError wraps a transport-level failure, retaining the originating request and any partial response that was received.
func (*RequestError) Error ¶
func (e *RequestError) Error() string
func (*RequestError) Unwrap ¶
func (e *RequestError) Unwrap() error
type Response ¶
type Response struct {
*http.Response
// Elapsed is the wall-clock time from sending the request to
// receiving the first byte of the response headers.
Elapsed time.Duration
// History is the redirect chain leading to this response, oldest
// first. Empty if no redirects occurred.
History []*Response
// contains filtered or unexported fields
}
Response wraps *http.Response with the goreqs ergonomic surface (Bytes, Text, JSON, RaiseForStatus, Links). The embedded *http.Response is part of the public API: drop down to net/http types whenever the goreqs sugar is not enough.
Body handling: the first call to Bytes/Text/JSON reads the body to EOF, closes it, and caches the bytes. Subsequent calls return the cached bytes; Body is replaced with a re-readable io.NopCloser over the cache so consumer code that ranges over Body still works.
When Opts.Stream is true, Bytes/Text/JSON are NOT called automatically by Client.Do, so the caller is responsible for reading and closing Body. In that mode the embedded *http.Response.Body is the live network stream.
func Get ¶
Get sends a GET request via DefaultClient.
Example ¶
Get sends a GET request via the package-level DefaultClient.
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello")
}))
defer s.Close()
resp, err := reqs.Get(context.Background(), s.URL)
if err != nil {
fmt.Println("error:", err)
return
}
body, _ := resp.Bytes()
fmt.Print(string(body))
Output: hello
Example (Params) ¶
ExampleGet_params shows attaching query parameters via Opts.Params.
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, r.URL.Query().Get("name"))
}))
defer s.Close()
resp, _ := reqs.Get(context.Background(), s.URL,
reqs.Opts{Params: url.Values{"name": {"alice"}}})
body, _ := resp.Bytes()
fmt.Print(string(body))
Output: alice
func Post ¶
Post sends a POST request via DefaultClient.
Example (Json) ¶
ExamplePost_json sends a JSON body.
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
_, _ = w.Write([]byte("ok"))
}))
defer s.Close()
resp, _ := reqs.Post(context.Background(), s.URL,
reqs.Opts{JSON: map[string]int{"x": 1}})
fmt.Println(resp.Header.Get("Content-Type"))
Output: application/json
func (*Response) ApparentEncoding ¶
ApparentEncoding sniffs the cached body for a charset (BOM, HTML meta, frequency heuristics). Returns "" when the body is empty or no encoding can be determined. Calling ApparentEncoding reads the body (via Bytes) if it has not been read yet.
func (*Response) Bytes ¶
Bytes reads the response body into memory and returns it. The first call closes the underlying body and caches the bytes; subsequent calls return the cache. After the first call, Body is replaced with a re-readable io.NopCloser over the cache.
func (*Response) Encoding ¶
Encoding returns the charset declared by the Content-Type header, or "" if none. This is the value Text uses unless ApparentEncoding falls back. Set r.encoding directly only via the setter SetEncoding (so we can clear caches if we add any later).
func (*Response) JSON ¶
JSON decodes the response body as JSON into v. When the Content-Type has no charset, the encoding is guessed from BOM/null patterns per RFC 4627 §3 (matching Python requests' guess_json_utf).
func (*Response) Links ¶
Links parses the Link response header into a map keyed by rel (or URL if rel is missing). Returns nil when the header is absent.
func (*Response) RaiseForStatus ¶
RaiseForStatus returns *HTTPError when StatusCode is in [400, 600), nil otherwise. Mirrors Python requests' raise_for_status.
Example ¶
ExampleResponse_RaiseForStatus shows error handling for non-2xx responses.
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r)
}))
defer s.Close()
resp, _ := reqs.Get(context.Background(), s.URL+"/missing")
if err := resp.RaiseForStatus(); err != nil {
fmt.Println("status:", resp.StatusCode)
}
Output: status: 404
func (*Response) SetEncoding ¶
SetEncoding overrides the encoding used by Text. Useful when the server lies about charset in Content-Type.
func (*Response) Text ¶
Text returns the response body decoded to a string. The encoding is determined in this order:
- The charset parameter of the Content-Type header.
- text/* default of ISO-8859-1; application/json default of utf-8.
- golang.org/x/net/html/charset.DetermineEncoding (BOM + HTML meta + heuristics).
- The raw bytes interpreted as UTF-8.
To override, set r.Encoding before calling Text.