client

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package client provides a small, dependency-free HTTP client for talking to JSON REST APIs. It is the single transport layer shared by every Azure DevOps service wrapper and by the 7pace Timetracker integration.

The client is intentionally generic: callers describe a request (method, path, query, body) and supply a destination for the decoded JSON response. Authentication is pluggable via the Authorizer interface so the same code serves both Azure DevOps (PAT Basic auth) and 7pace (bearer token).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type APIError

type APIError struct {
	Method     string // HTTP method of the failed request
	URL        string // request URL (path + query)
	StatusCode int    // HTTP status code
	Message    string // human-readable message extracted from the body
	TypeKey    string // Azure DevOps "typeKey", when present
	Body       string // raw response body (truncated)

	// RetryAfter is the raw "Retry-After" response header value (seconds, or
	// an HTTP-date), when present. Azure DevOps sets this on HTTP 429
	// responses once a caller exceeds its TSTU rate-limit budget; surfacing
	// it lets a caller (or the LLM driving this MCP server) know to wait
	// before retrying instead of treating the failure as opaque.
	RetryAfter string
}

APIError is a structured error returned for any non-2xx HTTP response. It preserves the HTTP status and, when available, the service-provided message so callers (and ultimately the LLM) get an actionable explanation rather than an opaque status code.

func (*APIError) Error

func (e *APIError) Error() string

Error implements the error interface.

type Authorizer

type Authorizer interface {
	// Authorize mutates the request to carry authentication.
	Authorize(*http.Request)
}

Authorizer applies authentication credentials to an outgoing request.

type BearerAuthorizer

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

BearerAuthorizer authenticates using an OAuth-style bearer token. It is used for 7pace Timetracker.

func NewBearerAuthorizer

func NewBearerAuthorizer(token string) *BearerAuthorizer

NewBearerAuthorizer builds a BearerAuthorizer for the given token.

func (*BearerAuthorizer) Authorize

func (a *BearerAuthorizer) Authorize(r *http.Request)

Authorize sets the Authorization header for bearer auth.

type Client

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

Client is a reusable JSON REST client bound to a base URL and an Authorizer. A Client is safe for concurrent use by multiple goroutines.

func New

func New(baseURL string, auth Authorizer, opts ...Option) (*Client, error)

New creates a Client for the given base URL and Authorizer.

func (*Client) Delete

func (c *Client) Delete(ctx context.Context, path string, query url.Values, out any) error

Delete performs a DELETE request, optionally decoding a response body.

func (*Client) Do

func (c *Client) Do(ctx context.Context, req Request) (*Response, error)

Do executes a request, decoding a successful JSON response into req.Out (when set) and returning a typed *APIError for non-2xx responses.

If Azure DevOps rejects the requested api-version (HTTP 400, "version not supported"), Do negotiates a supported version from the server's response and retries the request once. This transparently handles endpoints that require a "-preview" api-version without each caller having to know the exact suffix.

func (*Client) GetJSON

func (c *Client) GetJSON(ctx context.Context, path string, query url.Values, out any) error

GetJSON performs a GET request and decodes the response into out.

func (*Client) GetJSONVersion

func (c *Client) GetJSONVersion(ctx context.Context, path string, query url.Values, out any, apiVersion string) error

GetJSONVersion is like GetJSON but pins a specific api-version (e.g. for "-preview" endpoints).

func (*Client) PatchJSON

func (c *Client) PatchJSON(ctx context.Context, path string, query url.Values, body, out any, contentType string) error

PatchJSON performs a PATCH request with a JSON body and decodes the response. contentType may be empty to use "application/json"; Azure DevOps work-item updates require "application/json-patch+json".

func (*Client) PostJSON

func (c *Client) PostJSON(ctx context.Context, path string, query url.Values, body, out any) error

PostJSON performs a POST request with a JSON body and decodes the response.

func (*Client) PostJSONPatch

func (c *Client) PostJSONPatch(ctx context.Context, path string, body, out any) error

PostJSONPatch performs a POST with the "application/json-patch+json" content type required by Azure DevOps work item create operations.

func (*Client) PostJSONVersion

func (c *Client) PostJSONVersion(ctx context.Context, path string, body, out any, apiVersion string) error

PostJSONVersion is like PostJSON but pins a specific api-version.

func (*Client) PutJSON

func (c *Client) PutJSON(ctx context.Context, path string, query url.Values, body, out any) error

PutJSON performs a PUT request with a JSON body and decodes the response.

type List

type List[T any] struct {
	Count int `json:"count"`
	Value []T `json:"value"`
}

List is the standard Azure DevOps collection envelope: most list endpoints return {"count": N, "value": [...]}. Decode into List[T] to access the items.

type Option

type Option func(*Client)

Option configures a Client.

func WithAPIVersion

func WithAPIVersion(v string) Option

WithAPIVersion sets a default "api-version" query parameter applied to every request that does not specify its own. Azure DevOps requires this; 7pace encodes the version in the path and should leave it empty.

func WithCacheTTL added in v0.1.2

func WithCacheTTL(d time.Duration) Option

WithCacheTTL enables an in-memory cache for GET responses, valid for the given duration. A zero duration (the default) disables caching. The cache is invalidated in full whenever a write request through this Client succeeds, so cached data is never older than the client's own last write.

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

WithHTTPClient sets a custom *http.Client (e.g. for testing or proxies).

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent sets the User-Agent header sent on every request.

type PATAuthorizer

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

PATAuthorizer authenticates to Azure DevOps using a Personal Access Token.

Azure DevOps accepts a PAT via HTTP Basic auth with an empty username and the token as the password.

func NewPATAuthorizer

func NewPATAuthorizer(pat string) *PATAuthorizer

NewPATAuthorizer builds a PATAuthorizer for the given token.

func (*PATAuthorizer) Authorize

func (a *PATAuthorizer) Authorize(r *http.Request)

Authorize sets the Authorization header for Basic PAT auth.

type RawBody

type RawBody struct {
	Bytes       []byte
	ContentType string
}

RawBody captures an undecoded response body. Pass a *RawBody as Request.Out to receive the raw bytes (and content type) instead of JSON decoding, for endpoints that return plain text such as build/pipeline logs.

func (*RawBody) String

func (r *RawBody) String() string

String returns the raw body as a string.

type Request

type Request struct {
	// Method is the HTTP method (GET, POST, PATCH, PUT, DELETE).
	Method string

	// Path is appended to the client's base URL. A leading slash is optional.
	Path string

	// Query holds URL query parameters. The "api-version" parameter, if not
	// present here, is added from the client default when set.
	Query url.Values

	// Body, when non-nil, is JSON-encoded and sent as the request body.
	// If Body already implements io.Reader it is sent verbatim.
	Body any

	// ContentType overrides the request Content-Type. Defaults to
	// "application/json" when a body is present.
	ContentType string

	// APIVersion overrides the client's default api-version for this request.
	APIVersion string

	// Header holds extra request headers (e.g. "If-Match" for conditional
	// updates). These are applied after defaults, so they take precedence.
	Header http.Header

	// Out, when non-nil, receives the JSON-decoded response body.
	Out any
}

Request describes a single REST call.

type Response

type Response struct {
	StatusCode int
	Header     http.Header

	// ContinuationToken is the value of the x-ms-continuationtoken header used
	// by Azure DevOps to page through large result sets. Empty when absent.
	ContinuationToken string
}

Response carries metadata about a completed request. The decoded body, if requested, is written to Request.Out.

Jump to

Keyboard shortcuts

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