httpx

package
v1.135.0 Latest Latest
Warning

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

Go to latest
Published: Jun 1, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package httpx is the shared HTTP transport used by the Bitbucket Server/DC and Cloud API adapters. It handles request construction, authentication injection, JSON encoding/decoding, and error translation into backend.HTTPError.

Each adapter plugs in its own ErrorDecoder to parse backend-specific error response bodies, a ContentTypePolicy to control when Content-Type is set, and a Paginator to follow multi-page results.

Index

Constants

This section is empty.

Variables

View Source
var DefaultRetryPolicy = RetryPolicy{
	MaxAttempts:    3,
	InitialBackoff: 200 * time.Millisecond,
	MaxBackoff:     2 * time.Second,
	Jitter:         true,
}

DefaultRetryPolicy is 3 attempts, 200 ms → 2 s, with jitter.

Functions

func WithRetry added in v1.34.0

func WithRetry(ctx context.Context, policy RetryPolicy) context.Context

WithRetry returns a new context carrying policy. Pass it to any transport method (GetJSON, PostJSON, etc.) to enable retries for that call.

func WrapTransport added in v1.34.0

func WrapTransport(inner http.RoundTripper) http.RoundTripper

WrapTransport wraps inner with the httpx middleware stack.

Middleware order, outermost first (from the request's perspective):

retryRoundTripper → eTagRoundTripper → rateLimitRoundTripper → inner

Each call returns a fresh stack with its own ETag cache — entries are never shared across different http.Clients so responses for different auth identities or hosts cannot cross-contaminate each other.

retryRoundTripper is opt-in: it only retries when the request context carries a RetryPolicy (via WithRetry or Transport.WireRetry). eTagRoundTripper transparently sends If-None-Match on cached GETs and rewrites 304 responses to 200 with the cached body. rateLimitRoundTripper inspects X-RateLimit-* headers and blocks (honouring context cancellation) when Remaining hits zero.

Types

type Auth

type Auth struct {
	Token    string
	Username string
}

Auth holds credentials for a single host. If Token is non-empty Bearer auth is used; otherwise if Username is non-empty Basic auth is used with Username:Token as credentials.

type ContentTypePolicy added in v1.6.4

type ContentTypePolicy func(method string, hasBody bool) bool

ContentTypePolicy controls when the Content-Type: application/json header is added to a request. method is the HTTP method; hasBody is true when the request carries a non-nil body.

Use ContentTypeWhenBody for Bitbucket Cloud and ContentTypeAlwaysWrite for Bitbucket Server/DC.

var ContentTypeAlwaysWrite ContentTypePolicy = func(method string, hasBody bool) bool {
	return hasBody || (method != http.MethodGet && method != http.MethodHead)
}

ContentTypeAlwaysWrite sets Content-Type for every write method (POST, PUT, DELETE) even when the body is nil. Use this for Bitbucket Server/Data Center whose CSRF filter rejects write requests that omit Content-Type.

var ContentTypeWhenBody ContentTypePolicy = func(_ string, hasBody bool) bool {
	return hasBody
}

ContentTypeWhenBody sets Content-Type only when the request carries a body. Use this for Bitbucket Cloud, which returns HTTP 400 when an empty-body POST/PUT includes a Content-Type header (e.g. ApprovePR, DeclinePR, RequestChangesPR).

type Doer

type Doer interface {
	Do(req *http.Request) (*http.Response, error)
}

Doer is the transport interface for making HTTP requests. It is satisfied by *http.Client.

type ErrorDecoder

type ErrorDecoder func(body io.Reader) string

ErrorDecoder extracts a human-readable message from an error response body. Different Bitbucket products return different error envelopes, so each adapter supplies its own decoder.

type Paginator added in v1.6.4

type Paginator interface {
	// NextURL returns the absolute URL of the next page, or "" when there are
	// no more pages. currentURL is the absolute URL that produced responseBody.
	NextURL(currentURL string, responseBody []byte) string
}

Paginator extracts the next-page URL from a response body. Implementations live in each adapter package because the pagination envelope differs between Cloud ("next": "<absolute-url>") and Server/DC ("isLastPage": bool, "nextPageStart": N).

type RateLimitState added in v1.34.0

type RateLimitState struct {
	Limit     int
	Remaining int
	Reset     time.Time
}

RateLimitState holds parsed X-RateLimit-* header values.

type RetryPolicy added in v1.34.0

type RetryPolicy struct {
	MaxAttempts    int
	InitialBackoff time.Duration
	MaxBackoff     time.Duration
	Jitter         bool
}

RetryPolicy controls retry behaviour for a single request.

type Transport

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

Transport encapsulates auth injection and JSON helpers over a Doer.

func New

func New(doer Doer, baseURL string, auth Auth, decodeErr ErrorDecoder, ctPolicy ContentTypePolicy, paginator Paginator) *Transport

New constructs a Transport.

ctPolicy controls Content-Type header injection; pass ContentTypeWhenBody for Bitbucket Cloud or ContentTypeAlwaysWrite for Bitbucket Server/DC.

paginator is used by GetAllJSON to follow pages; pass nil if pagination is not required for this transport instance.

func (*Transport) DeleteJSON

func (t *Transport) DeleteJSON(path string, body any) error

DeleteJSON sends a DELETE request with an optional JSON body (body may be nil).

func (*Transport) GetAllJSON added in v1.6.4

func (t *Transport) GetAllJSON(path string, accumulate func([]byte) error) error

GetAllJSON fetches all pages starting at path by following the Transport's Paginator (if any). accumulate is called with the raw JSON bytes for each page. If no Paginator is configured only the first page is fetched.

The first request uses t.baseURL+path. Subsequent requests use the absolute URL returned by Paginator.NextURL, which lets each adapter embed the correct host in its next-page field.

func (*Transport) GetBytes added in v1.22.0

func (t *Transport) GetBytes(path string) ([]byte, error)

GetBytes GETs path and returns the raw response body. No Accept header is set so the backend serves the resource's native Content-Type — used for binary file content from the source/raw endpoints, where forcing Accept: text/plain corrupts non-text files.

func (*Transport) GetJSON

func (t *Transport) GetJSON(path string, v any) error

func (*Transport) GetStream added in v1.15.0

func (t *Transport) GetStream(path string) (io.ReadCloser, error)

GetStream GETs path and returns the response body for the caller to stream and Close. Sends Accept: text/plain so backends that content-negotiate (e.g. Bitbucket Server diff endpoints) return raw text. The body is closed on any non-2xx status; otherwise the caller owns it.

func (*Transport) GetText

func (t *Transport) GetText(path string) (string, error)

GetText GETs path and returns the raw body string. Sends Accept: text/plain so Bitbucket Server returns a unified diff rather than its JSON structured-diff format.

func (*Transport) PostJSON

func (t *Transport) PostJSON(path string, body, v any) error

func (*Transport) PostRaw added in v1.102.0

func (t *Transport) PostRaw(path string, body io.Reader, contentType string) error

PostRaw sends a POST request with the raw body and the given contentType (e.g. "multipart/form-data; boundary=..."). No JSON encoding or decoding is performed. Used for endpoints that accept multipart uploads.

func (*Transport) PutJSON

func (t *Transport) PutJSON(path string, body, v any) error

func (*Transport) PutRaw added in v1.102.0

func (t *Transport) PutRaw(path string, body io.Reader, contentType string) error

PutRaw sends a PUT request with the raw body and the given contentType. No JSON encoding or decoding is performed.

func (*Transport) UseDomainErrors added in v1.8.0

func (t *Transport) UseDomainErrors(host string) *Transport

UseDomainErrors enables classification of HTTP errors into typed backend.DomainError values on the way out of GetJSON / PostJSON / pagination helpers. host is attached to the returned DomainError so callers and the MCP surface know which Bitbucket instance produced the failure.

Adapters call this once during construction. When unset (the default), apiError continues to return the raw *backend.HTTPError for back-compat with existing tests.

func (*Transport) WireRetry added in v1.34.0

func (t *Transport) WireRetry(p RetryPolicy) *Transport

WireRetry sets a default RetryPolicy that is injected into the context of every outgoing request. This enables retry behaviour through all Transport helpers (GetJSON, PostJSON, etc.) without requiring callers to manage context values directly. Callers that want per-request control can still override the policy via WithRetry on the request context.

Jump to

Keyboard shortcuts

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