client

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package client is an HTTP client wrapping net/http.Client, with a testing surface built in: stub callbacks (Fake), response sequences, request recording, and assertions on what was sent. A PendingRequest is the fluent builder -- Get, Post, WithToken, WithHeaders, Timeout, Retry -- that materialises into an *http.Request and sends it.

The Factory holds the global configuration (middleware, options, stubs) and issues PendingRequest instances. It is the entry point for both the application and the test: a test calls Factory.Fake to intercept requests and Factory.AssertSent to verify them.

Why not a third-party HTTP client library

Go's net/http is the standard, and the testing surface -- Fake, Sequence, Record, AssertSent -- is the value this package adds. A wrapper around a third-party HTTP client would be a dependency for a dependency.

Index

Constants

View Source
const DefaultRequestExceptionTruncateAt = 120

DefaultRequestExceptionTruncateAt is how many characters of body summary go in the message, by default.

Variables

This section is empty.

Functions

func DontTruncate

func DontTruncate()

DontTruncate lets the whole body into the message of every request exception built from here on.

func Truncate

func Truncate()

Truncate restores the default truncation length for every request exception built from here on.

func TruncateAt

func TruncateAt(length int)

TruncateAt sets the truncation length for every request exception built from here on.

Types

type AssertionError

type AssertionError struct {
	Message string
}

AssertionError is returned by assertion methods when the assertion fails.

func (*AssertionError) Error

func (e *AssertionError) Error() string

type Batch

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

Batch collects requests to send concurrently, with callbacks for progress, error handling, and completion. It uses goroutines to send them.

func NewBatch

func NewBatch(f *Factory) *Batch

NewBatch creates a Batch backed by the given Factory.

func (*Batch) As

func (b *Batch) As(key string) *PendingRequest

As adds a named request to the batch.

func (*Batch) Before

func (b *Batch) Before(callback func()) *Batch

Before registers a callback that runs before any request is sent.

func (*Batch) Catch

func (b *Batch) Catch(callback func(error, int)) *Batch

Catch registers a callback that runs when a request fails.

func (*Batch) Concurrency

func (b *Batch) Concurrency(limit int) *Batch

Concurrency sets the maximum number of concurrent requests.

func (*Batch) Defer

func (b *Batch) Defer() *deferpkg.DeferredCallback

Defer sends the batch after the response has gone back to the browser, rather than while it is waiting.

The callback it hands back is the one the deferred-callback collection invokes; nothing here runs it, which is what makes it deferred.

func (*Batch) Finally

func (b *Batch) Finally(callback func()) *Batch

Finally registers a callback that runs after all requests complete, regardless of success or failure.

func (*Batch) Finished

func (b *Batch) Finished() bool

Finished reports whether the batch has finished executing.

func (*Batch) GetRequests

func (b *Batch) GetRequests() []batchRequest

GetRequests returns all requests in the batch.

func (*Batch) HasFailures

func (b *Batch) HasFailures() bool

HasFailures reports whether any request in the batch failed.

func (*Batch) NewRequest

func (b *Batch) NewRequest() *PendingRequest

NewRequest adds an unnamed request to the batch.

func (*Batch) ProcessedRequests

func (b *Batch) ProcessedRequests() int

ProcessedRequests returns the number of requests that have been processed.

func (*Batch) Progress

func (b *Batch) Progress(callback func(*Response, int)) *Batch

Progress registers a callback that runs after each successful request. It receives the Response and the index of the completed request.

func (*Batch) Send

func (b *Batch) Send() (map[string]*Response, error)

Send executes all requests in the batch.

func (*Batch) Then

func (b *Batch) Then(callback func(map[string]*Response)) *Batch

Then registers a callback that runs when all requests succeed.

type BatchInProgressError

type BatchInProgressError struct {
	HttpClientException
}

BatchInProgressError is returned by Batch.Send when that batch has already been sent. A batch collects its requests once and dispatches them once, so the second call is a mistake in the calling code rather than a transient failure -- going ahead with it would put every request in the batch on the wire a second time.

func NewBatchInProgressError

func NewBatchInProgressError() *BatchInProgressError

NewBatchInProgressError creates a BatchInProgressError.

type ConnectionException

type ConnectionException struct {
	HttpClientException
}

ConnectionException is returned when the request never reached the server: the host did not resolve, the connection was refused, or the transport gave up before a status line came back. There is no Response to inspect, because none arrived.

It is not the same failure as a response that arrived carrying a failing status -- that one is a RequestException. The retry callback is handed this error when the transport failed and the other one when the server answered badly, so a caller that treats them alike is retrying two different problems with one policy.

func NewConnectionException

func NewConnectionException(message string) *ConnectionException

NewConnectionException creates a ConnectionException.

type Dispatcher

type Dispatcher interface {
	// Dispatch delivers one event to whoever is listening.
	Dispatch(event any)
}

Dispatcher is the event sink the client uses: it fires RequestSending, ResponseReceived and ConnectionFailed.

It runs on the calling goroutine, so a listener that blocks blocks the request. Anything slow belongs on a queue.

type Factory

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

Factory is the entry point for the HTTP client layer. It holds global configuration — middleware, base options, stub callbacks — and issues PendingRequest instances through CreatePendingRequest. In a test, Fake installs a stub that intercepts every outgoing request; AssertSent verifies what was sent.

The zero value is usable: it creates a PendingRequest backed by http.DefaultClient with no stubs and no middleware.

func NewFactory

func NewFactory(client *http.Client) *Factory

NewFactory creates a Factory with the given HTTP client. If client is nil, http.DefaultClient is used.

func (*Factory) AllowStrayRequests

func (f *Factory) AllowStrayRequests(only ...string) *Factory

AllowStrayRequests allows stray requests, optionally limited to specific URLs. When only is empty, all stray requests are allowed.

func (*Factory) AssertNotSent

func (f *Factory) AssertNotSent(callback func(*http.Request) bool) error

AssertNotSent asserts that no request matching the callback was sent.

func (*Factory) AssertNothingSent

func (f *Factory) AssertNothingSent() error

AssertNothingSent asserts that no requests were sent at all.

func (*Factory) AssertSent

func (f *Factory) AssertSent(callback func(*http.Request) bool) error

AssertSent asserts that a request matching the callback was sent. The callback receives the sent *http.Request and returns true if it matches.

func (*Factory) AssertSentCount

func (f *Factory) AssertSentCount(count int) error

AssertSentCount asserts that exactly count requests were sent.

func (*Factory) AssertSentInOrder

func (f *Factory) AssertSentInOrder(callbacks ...func(*http.Request) bool) error

AssertSentInOrder asserts that requests matching the given callbacks were sent in the specified order.

func (*Factory) AssertSequencesAreEmpty

func (f *Factory) AssertSequencesAreEmpty() error

AssertSequencesAreEmpty asserts that all registered ResponseSequences have been fully consumed.

func (*Factory) Client

func (f *Factory) Client() *http.Client

Client returns the underlying *http.Client.

func (*Factory) CreatePendingRequest

func (f *Factory) CreatePendingRequest() *PendingRequest

CreatePendingRequest creates a new PendingRequest backed by this Factory.

func (*Factory) FailedConnection

func (f *Factory) FailedConnection(message string) StubCallback

FailedConnection is a stub that fails to connect.

When no message is given, the error names the host instead, because a test that asserts on the text is asserting on the host.

func (*Factory) FailedRequest

func (f *Factory) FailedRequest(body any, status int, headers http.Header) *RequestException

FailedRequest is the RequestException a stub hands back when it wants the caller to see a failure it can inspect.

func (*Factory) Fake

func (f *Factory) Fake(callbacks ...StubCallback) *Factory

Fake installs stub callbacks that intercept outgoing requests. When stubs are installed, requests are routed through them instead of the wire. Each callback receives the *http.Request; return a (*http.Response, nil) to simulate a successful response, or (nil, error) for a connection failure.

factory.Fake(func(r *http.Request) (*http.Response, error) {
    return client.NewResponse(200, `{"ok":true}`), nil
})

func (*Factory) FakeSequence

func (f *Factory) FakeSequence(urlPattern string) *ResponseSequence

FakeSequence registers a ResponseSequence for the given URL pattern. Each call to a matching URL consumes the next response in the sequence.

func (*Factory) GetDispatcher

func (f *Factory) GetDispatcher() Dispatcher

GetDispatcher is the dispatcher the client fires into, or nil when nobody is listening.

func (*Factory) GetGlobalMiddleware

func (f *Factory) GetGlobalMiddleware() []func(*http.Request, http.RoundTripper) http.RoundTripper

GetGlobalMiddleware is the middleware Factory.GlobalMiddleware added.

func (*Factory) GlobalMiddleware

func (f *Factory) GlobalMiddleware(middleware ...func(*http.Request, http.RoundTripper) http.RoundTripper) *Factory

GlobalMiddleware adds middleware applied to every request-response cycle.

func (*Factory) GlobalOptions

func (f *Factory) GlobalOptions(fn func(*http.Client)) *Factory

GlobalOptions sets global options on the underlying HTTP client.

func (*Factory) GlobalRequestMiddleware

func (f *Factory) GlobalRequestMiddleware(middleware ...func(*http.Request) error) *Factory

GlobalRequestMiddleware adds middleware applied before every request is sent.

func (*Factory) GlobalResponseMiddleware

func (f *Factory) GlobalResponseMiddleware(middleware ...func(*http.Response) error) *Factory

GlobalResponseMiddleware adds middleware applied after every response is received.

func (*Factory) Pool

func (f *Factory) Pool() *Pool

Pool creates a Pool for issuing concurrent requests.

func (*Factory) PreventStrayRequests

func (f *Factory) PreventStrayRequests(prevent bool) *Factory

PreventStrayRequests enables prevention of requests that do not match any stub. When enabled, an unmatched request fails with StrayRequestError.

func (*Factory) PreventingStrayRequests

func (f *Factory) PreventingStrayRequests() bool

PreventingStrayRequests reports whether stray request prevention is active.

func (*Factory) Record

func (f *Factory) Record() *Factory

Record enables request-response recording. Every sent request and its response (or error) is stored for later assertion.

func (*Factory) RecordRequestResponsePair

func (f *Factory) RecordRequestResponsePair(req *http.Request, resp *http.Response, err error)

RecordRequestResponsePair stores a request-response pair.

func (*Factory) Recorded

func (f *Factory) Recorded(callback func(RecordedPair) bool) []RecordedPair

Recorded returns the recorded request-response pairs, optionally filtered by the callback. If callback is nil, all pairs are returned.

func (*Factory) Response

func (f *Factory) Response(body any, status int, headers http.Header) *http.Response

Response is a stub response for a fake to hand back.

A nil body produces an empty body; anything that is not a string or a []byte is JSON-encoded and the Content-Type header is set.

It is a method and not a package function because the package already has a type named Response.

func (*Factory) Sequence

func (f *Factory) Sequence() *ResponseSequence

Sequence is a ResponseSequence the caller installs itself.

Factory.FakeSequence is the same sequence already wired to a URL pattern. This one is registered for AssertSequencesAreEmpty and handed back bare, for a caller that builds its own stub around it.

func (*Factory) SetDispatcher

func (f *Factory) SetDispatcher(dispatcher Dispatcher) *Factory

SetDispatcher sets the dispatcher the client fires its events into. It is a setter rather than a constructor argument, since most callers never need one.

func (*Factory) Stub deprecated

func (f *Factory) Stub(callback StubCallback) *Factory

Stub registers a stub callback for requests matching the given URL.

Deprecated: use Fake instead, which covers the same use case without the URL-matching layer that duplicates what callers already do in the callback.

func (*Factory) StubUrl

func (f *Factory) StubUrl(urlPattern string, callback StubCallback) *Factory

StubUrl fakes one URL pattern with one canned response.

It accepts the StubCallback that a status, a body, a closure or a sequence would all collapse into, and Factory.Response builds the canned one.

type HttpClientException

type HttpClientException struct {
	Message string
}

HttpClientException is the base exception type for HTTP client errors.

func (*HttpClientException) Error

func (e *HttpClientException) Error() string

type PendingRequest

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

PendingRequest is the fluent builder for an outgoing HTTP request. Every method returns the PendingRequest itself so that callers chain: WithToken, WithHeader, Timeout, Retry, and finally Get, Post, Put, Patch, Delete, Head, or Send.

The zero value is not usable; create one with Factory.CreatePendingRequest.

func (*PendingRequest) Accept

func (p *PendingRequest) Accept(ct string) *PendingRequest

Accept sets the Accept header.

func (*PendingRequest) AcceptJSON

func (p *PendingRequest) AcceptJSON() *PendingRequest

AcceptJSON sets the Accept header to application/json.

func (*PendingRequest) AfterResponse

func (p *PendingRequest) AfterResponse(callback func(*Response) error) *PendingRequest

AfterResponse registers a callback that runs after the Response is built.

func (*PendingRequest) AllowStrayRequests

func (p *PendingRequest) AllowStrayRequests(only []string) *PendingRequest

AllowStrayRequests allows stray requests for specific URLs.

func (*PendingRequest) AsForm

func (p *PendingRequest) AsForm() *PendingRequest

AsForm sets the body format to application/x-www-form-urlencoded.

func (*PendingRequest) AsJSON

func (p *PendingRequest) AsJSON() *PendingRequest

AsJSON sets the body format to JSON (the default).

func (*PendingRequest) AsMultipart

func (p *PendingRequest) AsMultipart() *PendingRequest

AsMultipart sets the body format to multipart/form-data.

func (*PendingRequest) Async

func (p *PendingRequest) Async(async bool) *PendingRequest

Async sets whether to send without waiting.

A verb called on an asynchronous request returns (nil, nil) and leaves a promise on PendingRequest.GetPromise; waiting on that promise is what makes the request go out, and what hands back the response.

func (*PendingRequest) Attach

func (p *PendingRequest) Attach(name, contents, filename string, headers map[string]string) *PendingRequest

Attach adds a file to the multipart form data.

func (*PendingRequest) BaseURL

func (p *PendingRequest) BaseURL(u string) *PendingRequest

BaseURL sets the base URL. Paths in Get/Post/etc. are resolved against it.

func (*PendingRequest) Batch

func (p *PendingRequest) Batch(callback func(*Batch)) *Batch

Batch executes a callback that adds requests to a Batch and sends them concurrently with progress and error callbacks.

func (*PendingRequest) BeforeSending

func (p *PendingRequest) BeforeSending(callback func(*http.Request) error) *PendingRequest

BeforeSending registers a callback that runs just before the request is sent.

func (*PendingRequest) BodyFormat

func (p *PendingRequest) BodyFormat(format string) *PendingRequest

BodyFormat sets the body format explicitly.

func (*PendingRequest) BuildClient

func (p *PendingRequest) BuildClient() *http.Client

BuildClient is the client this request will go out on.

func (*PendingRequest) ConnectTimeout

func (p *PendingRequest) ConnectTimeout(d time.Duration) *PendingRequest

ConnectTimeout sets the connection timeout.

func (*PendingRequest) ContentType

func (p *PendingRequest) ContentType(ct string) *PendingRequest

ContentType sets the Content-Type header.

func (*PendingRequest) CreateClient

func (p *PendingRequest) CreateClient(handler http.RoundTripper) *http.Client

CreateClient is a client configured the way this request needs it, without touching the shared one.

It takes the transport for the reason PendingRequest.SetHandler gives. A nil transport keeps whatever the client already had.

func (*PendingRequest) Dd

func (p *PendingRequest) Dd() *PendingRequest

Dd enables request/response dumping and then exits.

func (*PendingRequest) Delete

func (p *PendingRequest) Delete(urlStr string, data any) (*Response, error)

Delete sends a DELETE request.

func (*PendingRequest) DontTruncateExceptions

func (p *PendingRequest) DontTruncateExceptions() *PendingRequest

DontTruncateExceptions lets the whole body into this request's exception messages.

func (*PendingRequest) Dump

func (p *PendingRequest) Dump() *PendingRequest

Dump enables request/response dumping.

func (*PendingRequest) Get

func (p *PendingRequest) Get(urlStr string, query map[string]string) (*Response, error)

Get sends a GET request.

func (*PendingRequest) GetOptions

func (p *PendingRequest) GetOptions() map[string]any

GetOptions returns the current option configuration.

func (*PendingRequest) GetPromise

func (p *PendingRequest) GetPromise() promises.Promise

GetPromise is the promise this request left behind, or nil when it was not sent asynchronously.

Wait on it for a (*Response, error): the value is the *Response.

func (*PendingRequest) Head

func (p *PendingRequest) Head(urlStr string, query map[string]string) (*Response, error)

Head sends a HEAD request.

func (*PendingRequest) IsAllowedRequestUrl

func (p *PendingRequest) IsAllowedRequestUrl(url string) bool

IsAllowedRequestUrl reports whether a request to this URL may leave the process when no stub matched it.

Every URL is allowed until stray request prevention is on. After that only the patterns given to PendingRequest.AllowStrayRequests or Factory.AllowStrayRequests are, matched the way str.Is matches: a literal string, or one with * standing for any run of characters.

func (*PendingRequest) MaxRedirects

func (p *PendingRequest) MaxRedirects(max int) *PendingRequest

MaxRedirects sets how many redirects the request follows before it gives up.

func (*PendingRequest) MergeOptions

func (p *PendingRequest) MergeOptions(options ...map[string]any) map[string]any

MergeOptions is this request's options with the given ones laid over them, later maps winning.

Nothing in PendingRequest.GetOptions nests, so this is a flat merge.

func (*PendingRequest) Patch

func (p *PendingRequest) Patch(urlStr string, data any) (*Response, error)

Patch sends a PATCH request.

func (*PendingRequest) Pool

func (p *PendingRequest) Pool(callback func(*Pool), concurrency int) (map[string]*Response, error)

Pool executes a callback that adds requests to a Pool and sends them concurrently.

func (*PendingRequest) Post

func (p *PendingRequest) Post(urlStr string, data any) (*Response, error)

Post sends a POST request.

func (*PendingRequest) PreventStrayRequests

func (p *PendingRequest) PreventStrayRequests(prevent bool) *PendingRequest

PreventStrayRequests enables stray request prevention for this request.

func (*PendingRequest) Put

func (p *PendingRequest) Put(urlStr string, data any) (*Response, error)

Put sends a PUT request.

func (*PendingRequest) ReplaceHeaders

func (p *PendingRequest) ReplaceHeaders(headers map[string]string) *PendingRequest

ReplaceHeaders replaces all headers.

func (*PendingRequest) Retry

func (p *PendingRequest) Retry(times int, delay time.Duration, when func(*http.Response, error) bool, throw bool) *PendingRequest

Retry sets how many times the request may be attempted.

times is a total and includes the first send: Retry(3) makes at most three requests, not four. delay is what is waited between them.

when decides whether a failure is worth repeating and is handed the raw response, if one arrived, and the failure itself -- a *RequestException when the response failed, or the transport's error when the connection did. A nil when repeats every failure, which is the ordinary way to call this.

throw: when more than one attempt was asked for and the last one still failed, the failure comes back as an error rather than as a response. It is on by default.

func (*PendingRequest) RunBeforeSendingCallbacks

func (p *PendingRequest) RunBeforeSendingCallbacks(req *http.Request) error

RunBeforeSendingCallbacks runs what PendingRequest.BeforeSending registered, in the order it was registered, mutating req in place. It returns only what went wrong.

func (*PendingRequest) Send

func (p *PendingRequest) Send(method, urlStr string, query map[string]string, data any) (*Response, error)

Send sends the request. It is the central method that all HTTP verb methods delegate to.

func (*PendingRequest) SetClient

func (p *PendingRequest) SetClient(client *http.Client) *PendingRequest

SetClient sets the underlying HTTP client.

func (*PendingRequest) SetHandler

func (p *PendingRequest) SetHandler(handler http.RoundTripper) *PendingRequest

SetHandler sets the transport the request goes out on: the http.RoundTripper on the client, which is where a caller puts a recording or an offline transport.

func (*PendingRequest) Sink

func (p *PendingRequest) Sink(w io.Writer) *PendingRequest

Sink directs the response body to the given writer instead of reading it into memory.

func (*PendingRequest) Stub

func (p *PendingRequest) Stub(callback StubCallback) *PendingRequest

StubCallback registers a stub callback for this specific request.

func (*PendingRequest) Throw

func (p *PendingRequest) Throw(callback func(*Response, *RequestException)) *PendingRequest

Throw turns a failed response into an error.

The callback is a side effect only, never a substitute for building the exception: it used to run in place of returning it, so a callback that only logged made the failure vanish instead of surfacing as an error.

func (*PendingRequest) ThrowIf

func (p *PendingRequest) ThrowIf(condition bool) *PendingRequest

ThrowIf enables conditional throwing on failed responses.

func (*PendingRequest) ThrowUnless

func (p *PendingRequest) ThrowUnless(condition bool) *PendingRequest

ThrowUnless enables throwing unless the condition is true.

func (*PendingRequest) Timeout

func (p *PendingRequest) Timeout(d time.Duration) *PendingRequest

Timeout sets the request timeout.

func (*PendingRequest) TruncateExceptionsAt

func (p *PendingRequest) TruncateExceptionsAt(length int) *PendingRequest

TruncateExceptionsAt cuts the body summary of this request's exceptions at the given length.

func (*PendingRequest) WithAttributes

func (p *PendingRequest) WithAttributes(attrs map[string]any) *PendingRequest

WithAttributes attaches arbitrary attributes to the request.

func (*PendingRequest) WithBasicAuth

func (p *PendingRequest) WithBasicAuth(username, password string) *PendingRequest

WithBasicAuth sets HTTP Basic authentication.

func (*PendingRequest) WithBody

func (p *PendingRequest) WithBody(content io.Reader, contentType string) *PendingRequest

WithBody sets the raw request body with a given Content-Type.

func (*PendingRequest) WithCookies

func (p *PendingRequest) WithCookies(cookies []*http.Cookie, domain string) *PendingRequest

WithCookies sets cookies for the request domain.

func (*PendingRequest) WithDigestAuth

func (p *PendingRequest) WithDigestAuth(username, password string) *PendingRequest

WithDigestAuth sets HTTP Digest authentication.

func (*PendingRequest) WithHeader

func (p *PendingRequest) WithHeader(name, value string) *PendingRequest

WithHeader sets a single header.

func (*PendingRequest) WithHeaders

func (p *PendingRequest) WithHeaders(headers map[string]string) *PendingRequest

WithHeaders merges the given headers into the request headers.

func (*PendingRequest) WithMiddleware

func (p *PendingRequest) WithMiddleware(mw ...func(*http.Request, http.RoundTripper) http.RoundTripper) *PendingRequest

WithMiddleware adds transport-level middleware.

func (*PendingRequest) WithOptions

func (p *PendingRequest) WithOptions(fn func(*http.Client)) *PendingRequest

WithOptions sets arbitrary options on the underlying HTTP client.

func (*PendingRequest) WithQueryParameters

func (p *PendingRequest) WithQueryParameters(params map[string]string) *PendingRequest

WithQueryParameters adds query parameters to the request URL.

func (*PendingRequest) WithRequestMiddleware

func (p *PendingRequest) WithRequestMiddleware(mw ...func(*http.Request) error) *PendingRequest

WithRequestMiddleware adds request-level middleware (runs before send).

func (*PendingRequest) WithResponseMiddleware

func (p *PendingRequest) WithResponseMiddleware(mw ...func(*http.Response) error) *PendingRequest

WithResponseMiddleware adds response-level middleware (runs after receive).

func (*PendingRequest) WithToken

func (p *PendingRequest) WithToken(token string, tokenType string) *PendingRequest

WithToken sets a Bearer token (or custom token type).

func (*PendingRequest) WithURLParameters

func (p *PendingRequest) WithURLParameters(params map[string]string) *PendingRequest

WithURLParameters sets URL template parameters.

func (*PendingRequest) WithUserAgent

func (p *PendingRequest) WithUserAgent(ua string) *PendingRequest

WithUserAgent sets the User-Agent header.

func (*PendingRequest) WithoutRedirecting

func (p *PendingRequest) WithoutRedirecting() *PendingRequest

WithoutRedirecting disables automatic redirect following.

func (*PendingRequest) WithoutVerifying

func (p *PendingRequest) WithoutVerifying() *PendingRequest

WithoutVerifying disables TLS certificate verification.

type Pool

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

Pool collects concurrent HTTP requests and sends them as a batch. Each request is keyed either by a numeric index (NewRequest) or by a string key (As).

func NewPool

func NewPool(f *Factory) *Pool

NewPool creates a Pool backed by the given Factory.

func (*Pool) As

func (p *Pool) As(key string) *PendingRequest

As adds a request with a named key.

func (*Pool) GetRequests

func (p *Pool) GetRequests() []poolRequest

GetRequests returns all pending requests in the pool.

func (*Pool) NewRequest

func (p *Pool) NewRequest() *PendingRequest

NewRequest adds a request with a numeric key.

The key counts only the unnamed requests: a pool of As("a"), NewRequest(), As("b"), NewRequest() answers under "a", "0", "b" and "1".

func (*Pool) Send

func (p *Pool) Send(concurrency int) (map[string]*Response, error)

Send sends all requests in the pool concurrently and returns a map of key → Response. If concurrency is 0, all requests run concurrently.

type RecordedPair

type RecordedPair struct {
	Request  *http.Request
	Response *http.Response
	Error    error
}

RecordedPair is a request-response pair stored during recording.

type Request

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

Request wraps *http.Request and adds inspection methods for method, URL, headers, body, and content-type detection, for inspecting outgoing HTTP client requests in stubs and assertions.

func NewRequest

func NewRequest(req *http.Request) *Request

NewRequest creates a Request from an *http.Request. The body is read eagerly so that it can be inspected multiple times.

func (*Request) Attributes

func (r *Request) Attributes() map[string]any

Attributes returns the request attributes.

func (*Request) Body

func (r *Request) Body() string

Body returns the request body as a string.

func (*Request) Data

func (r *Request) Data() map[string]any

Data returns the decoded request data (form or JSON).

func (*Request) HTTPRequest

func (r *Request) HTTPRequest() *http.Request

HTTPRequest returns the underlying *http.Request.

func (*Request) HasFile

func (r *Request) HasFile(name, value, filename string) bool

HasFile reports whether the request has a file with the given name in its multipart body.

func (*Request) HasHeader

func (r *Request) HasHeader(key string, value string) bool

HasHeader reports whether the request has the given header, and optionally whether it has the given value.

func (*Request) HasHeaders

func (r *Request) HasHeaders(headers map[string]string) bool

HasHeaders reports whether the request has all the given headers.

func (*Request) Header

func (r *Request) Header(key string) []string

Header returns the values for a given header key.

func (*Request) Headers

func (r *Request) Headers() http.Header

Headers returns all headers.

func (*Request) IsForm

func (r *Request) IsForm() bool

IsForm reports whether the Content-Type is application/x-www-form-urlencoded.

func (*Request) IsJSON

func (r *Request) IsJSON() bool

IsJSON reports whether the Content-Type is application/json.

func (*Request) IsMultipart

func (r *Request) IsMultipart() bool

IsMultipart reports whether the Content-Type is multipart/form-data.

func (*Request) Method

func (r *Request) Method() string

Method returns the HTTP method.

func (*Request) SetRequestAttributes

func (r *Request) SetRequestAttributes(attrs map[string]any) *Request

SetRequestAttributes sets the request attributes.

func (*Request) String

func (r *Request) String() string

String returns a human-readable representation of the request.

func (*Request) URL

func (r *Request) URL() string

URL returns the full URL string.

func (*Request) WithData

func (r *Request) WithData(data map[string]any) *Request

WithData sets the decoded request data.

type RequestException

type RequestException struct {
	HttpClientException
	Response *Response

	// TruncateExceptionsAt is the per-instance override of the
	// package-level truncation length. Nil means the package-level
	// [TruncateAt] decides; a pointer to zero lets the whole body through.
	TruncateExceptionsAt *int

	// HasBeenSummarized is whether Report has already rebuilt the message
	// once.
	HasBeenSummarized bool
}

RequestException is returned when a response did come back and the caller asked for a failing one to be treated as an error: Response.Throw, Response.ThrowIfStatus and the retry loop that ran out of attempts all build one. The response stays on the value, so whatever handles the error can still read the status, the headers and the body.

Its message is the status code followed by a summary of the body, cut at the truncation length so that one log line does not swallow a whole HTML error page. TruncateExceptionsAt decides that length when it is set on the instance; otherwise the package-level TruncateAt does.

func NewRequestException

func NewRequestException(resp *Response, truncateExceptionsAt *int) *RequestException

NewRequestException creates a RequestException from a failed Response.

truncateExceptionsAt: nil defers to TruncateAt, a pointer to zero lets the whole body through, and a pointer to a positive length cuts the body summary there.

func (*RequestException) Report

func (e *RequestException) Report() bool

Report rebuilds the message from the response once, and returns false so that a caller's own exception handler carries on with its own reporting.

type Response

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

Response wraps *http.Response and adds inspection, JSON decoding, and error-throwing methods. The body is read eagerly so that the caller can call Body, JSON, and Collect repeatedly without draining the stream.

func NewResponse

func NewResponse(resp *http.Response) *Response

NewResponse creates a Response from an *http.Response. The body is read eagerly.

func NewResponseFromBytes

func NewResponseFromBytes(status int, body []byte, headers http.Header) *Response

NewResponseFromBytes creates a Response from raw bytes and a status code. This is useful in stubs and tests.

func (*Response) Accepted

func (r *Response) Accepted() bool

Accepted reports whether the status is 202.

func (*Response) BadRequest

func (r *Response) BadRequest() bool

BadRequest reports whether the status is 400.

func (*Response) Body

func (r *Response) Body() string

Body returns the response body as a string.

func (*Response) ClientError

func (r *Response) ClientError() bool

ClientError reports whether the status code is 4xx.

func (*Response) Close

func (r *Response) Close() error

Close closes the response body. It is safe to call multiple times.

func (*Response) Collect

func (r *Response) Collect(key string) ([]map[string]any, error)

Collect decodes the JSON body and returns it as a slice of maps.

func (*Response) Conflict

func (r *Response) Conflict() bool

Conflict reports whether the status is 409.

func (*Response) Cookies

func (r *Response) Cookies() []*http.Cookie

Cookies returns the cookies set by the response.

func (*Response) Created

func (r *Response) Created() bool

Created reports whether the status is 201.

func (*Response) DdHeaders

func (r *Response) DdHeaders()

DdHeaders dumps the headers and ends the process.

func (*Response) DontTruncateExceptions

func (r *Response) DontTruncateExceptions() *Response

DontTruncateExceptions lets the whole body into this response's exception message.

func (*Response) DumpHeaders

func (r *Response) DumpHeaders() *Response

DumpHeaders writes the response headers out where the process can see them.

func (*Response) EffectiveURI

func (r *Response) EffectiveURI() string

EffectiveURI returns the effective request URI (after redirects).

func (*Response) Failed

func (r *Response) Failed() bool

Failed reports whether the response is a client or server error (4xx or 5xx).

func (*Response) Forbidden

func (r *Response) Forbidden() bool

Forbidden reports whether the status is 403.

func (*Response) Found

func (r *Response) Found() bool

Found reports whether the status is 302.

func (*Response) HTTPResponse

func (r *Response) HTTPResponse() *http.Response

HTTPResponse returns the underlying *http.Response.

func (*Response) HandlerStats

func (r *Response) HandlerStats() map[string]any

HandlerStats returns basic timing information about the request.

func (*Response) Header

func (r *Response) Header(name string) string

Header returns the value of a response header.

func (*Response) Headers

func (r *Response) Headers() http.Header

Headers returns all response headers.

func (*Response) JSON

func (r *Response) JSON(key string, defaultValue any) (any, error)

JSON decodes the response body as JSON. If key is non-empty, it extracts a nested value using dot notation (e.g., "data.user.name").

func (*Response) MovedPermanently

func (r *Response) MovedPermanently() bool

MovedPermanently reports whether the status is 301.

func (*Response) NoContent

func (r *Response) NoContent() bool

NoContent reports whether the status is 204.

func (*Response) NotFound

func (r *Response) NotFound() bool

NotFound reports whether the status is 404.

func (*Response) NotModified

func (r *Response) NotModified() bool

NotModified reports whether the status is 304.

func (*Response) OK

func (r *Response) OK() bool

OK reports whether the status is 200.

func (*Response) Object

func (r *Response) Object(v any) error

Object decodes the JSON body into the given value.

func (*Response) OnError

func (r *Response) OnError(callback func(*Response) error) error

OnError calls the callback if the response indicates a failure.

func (*Response) PaymentRequired

func (r *Response) PaymentRequired() bool

PaymentRequired reports whether the status is 402.

func (*Response) Reason

func (r *Response) Reason() string

Reason is the reason phrase the server sent.

net/http keeps the whole status line, so the code is trimmed off the front of it. When there is no status line -- a stubbed response -- the registered text for the code stands in, which is what the server would have sent.

func (*Response) Redirect

func (r *Response) Redirect() bool

Redirect reports whether the status code is 3xx.

func (*Response) RequestTimeout

func (r *Response) RequestTimeout() bool

RequestTimeout reports whether the status is 408.

func (*Response) Resource

func (r *Response) Resource() []byte

Resource returns the raw body bytes.

func (*Response) ServerError

func (r *Response) ServerError() bool

ServerError reports whether the status code is >= 500.

func (*Response) Status

func (r *Response) Status() int

Status returns the HTTP status code.

func (*Response) StatusText

func (r *Response) StatusText() string

StatusText returns the HTTP status text.

func (*Response) Successful

func (r *Response) Successful() bool

Successful reports whether the status code is 2xx.

func (*Response) Throw

func (r *Response) Throw(callback func(*Response, *RequestException)) error

Throw is the RequestException a failed response carries, or nil when it did not fail.

The callback is a side effect and never a substitute for the exception: it used to return the callback's own error instead, so a callback that only logged and returned nil made a 500 disappear. It also used to hand the callback one argument instead of two -- the response and the exception.

func (*Response) ThrowIf

func (r *Response) ThrowIf(condition bool, callback func(*Response, *RequestException)) error

ThrowIf throws when the condition holds and the response failed. The callback is the side effect Response.Throw describes.

func (*Response) ThrowIfClientError

func (r *Response) ThrowIfClientError() error

ThrowIfClientError throws when the response is a 4xx.

func (*Response) ThrowIfServerError

func (r *Response) ThrowIfServerError() error

ThrowIfServerError throws when the response is a 5xx.

func (*Response) ThrowIfStatus

func (r *Response) ThrowIfStatus(statusCode int) error

ThrowIfStatus throws when the response carries the given status code.

It does not consult Failed: a RequestException is returned the moment the status matches, whatever the status is, which is what makes ThrowIfStatus(201) a usable assertion. This used to go through Throw, which returns nil for anything below 400, so every status a caller could name under 400 was silently accepted -- the mirror image of ThrowUnlessStatus, which was already right.

func (*Response) ThrowUnless

func (r *Response) ThrowUnless(condition bool) error

ThrowUnless calls throw unless the condition is true.

func (*Response) ThrowUnlessStatus

func (r *Response) ThrowUnlessStatus(statusCode int) error

ThrowUnlessStatus throws unless the response carries the given status code.

func (*Response) ToException

func (r *Response) ToException() *RequestException

ToException is the RequestException this response would throw, or nil when it did not fail.

Callers that assign it to an error must check for nil before returning it, because a nil pointer in a non-nil interface is not a nil error.

func (*Response) TooManyRequests

func (r *Response) TooManyRequests() bool

TooManyRequests reports whether the status is 429.

func (*Response) TruncateExceptionsAt

func (r *Response) TruncateExceptionsAt(length int) *Response

TruncateExceptionsAt cuts the body summary of this response's exception at the given length.

func (*Response) Unauthorized

func (r *Response) Unauthorized() bool

Unauthorized reports whether the status is 401.

func (*Response) UnprocessableContent

func (r *Response) UnprocessableContent() bool

UnprocessableContent is the 422 check under the name the current RFC gives it. Response.UnprocessableEntity is the same check under the name the older RFC gave it; both are kept for callers who know the status by either name.

func (*Response) UnprocessableEntity

func (r *Response) UnprocessableEntity() bool

UnprocessableEntity reports whether the status is 422.

type ResponseSequence

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

ResponseSequence provides an ordered sequence of stub responses that are returned one at a time as requests are made. When the sequence is exhausted, the next request returns an error (or a default if one is configured).

func NewResponseSequence

func NewResponseSequence() *ResponseSequence

NewResponseSequence creates an empty ResponseSequence.

func (*ResponseSequence) AsStub

func (s *ResponseSequence) AsStub(urlPattern string) StubCallback

AsStub returns a StubCallback that consumes responses from this sequence.

func (*ResponseSequence) DontFailWhenEmpty

func (s *ResponseSequence) DontFailWhenEmpty() *ResponseSequence

DontFailWhenEmpty prevents the sequence from returning an error when exhausted.

func (*ResponseSequence) IsEmpty

func (s *ResponseSequence) IsEmpty() bool

IsEmpty reports whether the sequence has any remaining responses.

func (*ResponseSequence) Push

func (s *ResponseSequence) Push(status int, body string, headers http.Header) *ResponseSequence

Push adds a response to the sequence.

func (*ResponseSequence) PushFailedConnection

func (s *ResponseSequence) PushFailedConnection(message string) *ResponseSequence

PushFailedConnection adds a connection failure to the sequence.

func (*ResponseSequence) PushFile

func (s *ResponseSequence) PushFile(filePath string, status int, headers http.Header) *ResponseSequence

PushFile adds a response whose body is read from the given file path.

func (*ResponseSequence) PushResponse

func (s *ResponseSequence) PushResponse(resp *http.Response) *ResponseSequence

PushResponse adds a raw *http.Response to the sequence.

func (*ResponseSequence) PushStatus

func (s *ResponseSequence) PushStatus(status int, headers http.Header) *ResponseSequence

PushStatus adds a response with only a status code (no body).

func (*ResponseSequence) WhenEmpty

func (s *ResponseSequence) WhenEmpty(status int, body string, headers http.Header) *ResponseSequence

WhenEmpty configures the default response returned when the sequence is exhausted. When set, the sequence does not fail when empty.

type StrayRequestError

type StrayRequestError struct {
	URI string
}

StrayRequestError is returned when a request is made that does not match any stub and stray request prevention is enabled.

func NewStrayRequestError

func NewStrayRequestError(uri string) *StrayRequestError

NewStrayRequestError creates a StrayRequestError.

func (*StrayRequestError) Error

func (e *StrayRequestError) Error() string

type StubCallback

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

StubCallback receives the outgoing *http.Request and returns a response or an error. Return (nil, nil) to let the request fall through to the next stub or to the wire.

Directories

Path Synopsis
Package concerns is intentionally empty.
Package concerns is intentionally empty.
Package events holds the events dispatched during an HTTP client request lifecycle: RequestSending, ResponseReceived and ConnectionFailed.
Package events holds the events dispatched during an HTTP client request lifecycle: RequestSending, ResponseReceived and ConnectionFailed.
Package promises provides the two promise-like types the HTTP client returns from an asynchronous request: FluentPromise and LazyPromise.
Package promises provides the two promise-like types the HTTP client returns from an asynchronous request: FluentPromise and LazyPromise.

Jump to

Keyboard shortcuts

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