client

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Feb 17, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DefaultBaseURL is the default base URL for the Workbrew API
	DefaultBaseURL = "https://console.workbrew.com"

	// DefaultAPIVersion is the default API version
	DefaultAPIVersion = "v0"

	// APIVersionHeader is the header name for the API version
	APIVersionHeader = "X-Workbrew-API-Version"

	// AuthorizationHeader is the header name for the authorization token
	AuthorizationHeader = "Authorization"

	// UserAgentBase is the base user agent string prefix
	UserAgentBase = "go-api-sdk-workbrew"

	// DefaultTimeout is the default HTTP client timeout in seconds
	DefaultTimeout = 120

	// MaxRetries is the maximum number of retries for failed requests
	MaxRetries = 3

	// RetryWaitTime is the wait time between retries in seconds
	RetryWaitTime = 2

	// RetryMaxWaitTime is the maximum wait time between retries in seconds
	RetryMaxWaitTime = 10
)
View Source
const (
	// Success status codes
	StatusOK      = 200 // Successful GET requests
	StatusCreated = 201 // Successful POST requests

	// Client error status codes
	StatusBadRequest          = 400 // Bad request, invalid arguments
	StatusUnauthorized        = 401 // Authentication required, invalid API key
	StatusForbidden           = 403 // Forbidden operation
	StatusNotFound            = 404 // Resource not found
	StatusConflict            = 409 // Resource already exists
	StatusUnprocessableEntity = 422 // Validation errors
	StatusFailedDependency    = 424 // Request depended on another request that failed
	StatusTooManyRequests     = 429 // Rate limit exceeded

	// Server error status codes
	StatusInternalServerError = 500 // Server-side error
	StatusBadGateway          = 502 // Gateway error
	StatusServiceUnavailable  = 503 // Transient error, service temporarily unavailable
	StatusGatewayTimeout      = 504 // Deadline exceeded
)

HTTP Status Codes

View Source
const (
	FormatJSON = "json"
	FormatCSV  = "csv"
)

Response format constants

View Source
const (
	ContentTypeJSON = "application/json"
	AcceptJSON      = "application/json"
)

HTTP headers

View Source
const Version = "1.0.0"

Version is the SDK version

Variables

This section is empty.

Functions

func GetRateLimitHeaders

func GetRateLimitHeaders(resp *interfaces.Response) (limit, remaining, reset, retryAfter string)

GetRateLimitHeaders extracts Workbrew API rate limiting headers from the response. These headers indicate the API quota limits and current usage.

Parameters:

  • resp: The response containing rate limit headers

Returns:

  • limit: Maximum number of requests allowed (X-Api-Quota-Limit)
  • remaining: Number of requests remaining (X-Api-Quota-Remaining)
  • reset: Unix timestamp when quota resets (X-Api-Quota-Reset)
  • retryAfter: Seconds to wait before retrying (Retry-After)

Example:

limit, remaining, reset, retryAfter := client.GetRateLimitHeaders(resp)
if remaining == "0" {
    log.Printf("Rate limit exceeded. Resets at: %s", reset)
    time.Sleep(time.Duration(retryAfter) * time.Second)
}

func GetResponseHeader

func GetResponseHeader(resp *interfaces.Response, key string) string

GetResponseHeader retrieves a single header value from the response by key. Header lookup is case-insensitive following HTTP standards.

Parameters:

  • resp: The response containing headers
  • key: The header name to retrieve (case-insensitive)

Returns:

  • string: The header value, or empty string if not found

Example:

contentType := client.GetResponseHeader(resp, "Content-Type")

func GetResponseHeaders

func GetResponseHeaders(resp *interfaces.Response) http.Header

GetResponseHeaders returns all HTTP headers from the response.

Parameters:

  • resp: The response containing headers

Returns:

  • http.Header: All response headers, or empty map if response is nil

func IsBadRequest

func IsBadRequest(err error) bool

IsBadRequest checks if the error is a bad request error (400). This typically indicates invalid request parameters or malformed JSON.

Parameters:

  • err: The error to check

Returns:

  • bool: True if the error is a 400 Bad Request, false otherwise

Example:

if client.IsBadRequest(err) {
    log.Println("Invalid request parameters:", err)
}

func IsConflict

func IsConflict(err error) bool

IsConflict checks if the error is a conflict error (409) - resource already exists

func IsDeadlineExceeded

func IsDeadlineExceeded(err error) bool

IsDeadlineExceeded checks if the operation took too long to complete (504)

func IsForbidden

func IsForbidden(err error) bool

IsForbidden checks if the error is a forbidden error (403) This typically indicates free tier plan restrictions per swagger spec

func IsFreeTierError

func IsFreeTierError(err error) bool

IsFreeTierError checks if the error is specifically a free tier restriction error (403) Per swagger spec, these errors have messages about plan upgrades

func IsNotFound

func IsNotFound(err error) bool

IsNotFound checks if the error is a not found error (404)

func IsRateLimited

func IsRateLimited(err error) bool

IsRateLimited checks if the error is a rate limit error (429). This indicates too many requests have been made within the rate limit window.

Parameters:

  • err: The error to check

Returns:

  • bool: True if the error is a 429 Too Many Requests, false otherwise

Example with retry logic:

if client.IsRateLimited(err) {
    _, _, reset, retryAfter := client.GetRateLimitHeaders(resp)
    log.Printf("Rate limited. Retry after: %s seconds", retryAfter)
    time.Sleep(time.Duration(retryAfterInt) * time.Second)
    // Retry the request
}

func IsResponseError

func IsResponseError(resp *interfaces.Response) bool

IsResponseError returns true if the response status code indicates an error (4xx or 5xx).

Parameters:

  • resp: The response to check

Returns:

  • bool: True if status code is 400 or higher, false otherwise

func IsResponseSuccess

func IsResponseSuccess(resp *interfaces.Response) bool

IsResponseSuccess returns true if the response status code indicates success (2xx).

Parameters:

  • resp: The response to check

Returns:

  • bool: True if status code is in the 200-299 range, false otherwise

func IsServerError

func IsServerError(err error) bool

IsServerError checks if the error is a server error (5xx)

func IsTransient

func IsTransient(err error) bool

IsTransient checks if the error is transient and safe to retry. Returns true for 503 (Service Unavailable) and 504 (Gateway Timeout). These errors are typically temporary and the request may succeed on retry.

Parameters:

  • err: The error to check

Returns:

  • bool: True if the error is retryable (503 or 504), false otherwise

Example with exponential backoff:

if client.IsTransient(err) {
    for attempt := 0; attempt < 3; attempt++ {
        time.Sleep(time.Duration(math.Pow(2, float64(attempt))) * time.Second)
        result, _, err := client.Get(ctx, path, params, headers, &data)
        if err == nil || !client.IsTransient(err) {
            break
        }
    }
}

func IsUnauthorized

func IsUnauthorized(err error) bool

IsUnauthorized checks if the error is an authentication error (401)

func IsValidationError

func IsValidationError(err error) bool

IsValidationError checks if the error is a validation/unprocessable entity error (422) Per swagger: "Arguments cannot include `&&`", "Brewfile has an invalid line", etc.

func ParseErrorResponse

func ParseErrorResponse(body []byte, statusCode int, status, method, endpoint string, logger *zap.Logger) error

ParseErrorResponse parses an HTTP error response body into an APIError. It attempts to parse the response as JSON and falls back to using the raw body as the message.

Parameters:

  • body: Raw response body bytes
  • statusCode: HTTP status code
  • status: HTTP status text (e.g., "404 Not Found")
  • method: HTTP method used
  • endpoint: API endpoint path
  • logger: Logger for recording error details

Returns:

  • error: APIError containing parsed error information

Example usage:

if resp.IsError() {
    return ParseErrorResponse(resp.Body(), resp.StatusCode(), resp.Status(), "GET", "/api/brewfiles", logger)
}

func SetupAuthentication

func SetupAuthentication(client *resty.Client, authConfig *AuthConfig, logger *zap.Logger) error

SetupAuthentication configures the HTTP client with bearer token authentication. The API key is set once during client initialization and cannot be changed.

Parameters:

  • client: The resty HTTP client to configure
  • authConfig: Authentication configuration containing API key and version
  • logger: Logger instance for logging authentication setup

Returns:

  • error: Any error encountered during authentication setup

Types

type APIError

type APIError struct {
	Message string   `json:"message"`          // Main error message
	Errors  []string `json:"errors,omitempty"` // Array of detailed error messages

	// HTTP response details
	StatusCode int    // HTTP status code
	Status     string // HTTP status text
	Endpoint   string // API endpoint that returned the error
	Method     string // HTTP method used
}

APIError represents an error response from the Workbrew API. It contains both the high-level error message and detailed validation errors.

The error structure matches the Workbrew API swagger specification:

{
  "message": "string",
  "errors": ["string"]
}

Example error response:

{
  "message": "Validation failed",
  "errors": [
    "Field 'name' is required",
    "Field 'content' must not be empty"
  ]
}

Use the helper functions (IsUnauthorized, IsNotFound, etc.) to check for specific error types.

func (*APIError) Error

func (e *APIError) Error() string

Error implements the error interface. It formats the error message with context including HTTP method, endpoint, and status code.

Returns:

  • string: Formatted error message with full context

Example output:

"Workbrew API error (422 Unprocessable Entity) at POST /api/v1/brewfiles: Validation failed - [Field 'name' is required]"

type AuthConfig

type AuthConfig struct {
	// APIKey is the bearer token for authentication
	APIKey string

	// APIVersion is the API version (defaults to v0)
	APIVersion string
}

AuthConfig holds authentication configuration for the Workbrew API.

func (*AuthConfig) Validate

func (a *AuthConfig) Validate() error

Validate checks if the authentication configuration is valid.

type ClientOption

type ClientOption func(*Transport) error

ClientOption is a function type for configuring the Transport

func WithAPIKey

func WithAPIKey(apiKey string) ClientOption

WithAPIKey allows setting the API key during client initialization. The API key cannot be changed after the client is created.

func WithAPIVersion

func WithAPIVersion(version string) ClientOption

WithAPIVersion sets a custom API version

func WithBaseURL

func WithBaseURL(baseURL string) ClientOption

WithBaseURL sets a custom base URL for the API client

func WithClientCertificate

func WithClientCertificate(certFile, keyFile string) ClientOption

WithClientCertificate sets a client certificate for mutual TLS authentication Loads certificate from PEM-encoded files

func WithClientCertificateFromString

func WithClientCertificateFromString(certPEM, keyPEM string) ClientOption

WithClientCertificateFromString sets a client certificate from PEM-encoded strings

func WithCustomAgent

func WithCustomAgent(customAgent string) ClientOption

WithCustomAgent allows appending a custom identifier to the default user agent Format: "go-api-sdk-workbrew/1.0.0; <customAgent>; gzip"

func WithDebug

func WithDebug() ClientOption

WithDebug enables debug mode which logs request and response details

func WithGlobalHeader

func WithGlobalHeader(key, value string) ClientOption

WithGlobalHeader sets a global header that will be included in all requests Per-request headers will override global headers with the same key

func WithGlobalHeaders

func WithGlobalHeaders(headers map[string]string) ClientOption

WithGlobalHeaders sets multiple global headers at once

func WithInsecureSkipVerify

func WithInsecureSkipVerify() ClientOption

WithInsecureSkipVerify disables TLS certificate verification (USE WITH CAUTION) This should ONLY be used for testing/development with self-signed certificates

func WithLogger

func WithLogger(logger *zap.Logger) ClientOption

WithLogger sets a custom logger for the client

func WithMinTLSVersion

func WithMinTLSVersion(minVersion uint16) ClientOption

WithMinTLSVersion sets the minimum TLS version for connections Common values: tls.VersionTLS12, tls.VersionTLS13

func WithProxy

func WithProxy(proxyURL string) ClientOption

WithProxy sets an HTTP proxy for all requests Example: "http://proxy.company.com:8080" or "socks5://127.0.0.1:1080"

func WithRetryCount

func WithRetryCount(count int) ClientOption

WithRetryCount sets the number of retries for failed requests

func WithRetryMaxWaitTime

func WithRetryMaxWaitTime(maxWaitTime time.Duration) ClientOption

WithRetryMaxWaitTime sets the maximum wait time between retry attempts The wait time increases exponentially with each retry up to this maximum

func WithRetryWaitTime

func WithRetryWaitTime(waitTime time.Duration) ClientOption

WithRetryWaitTime sets the default wait time between retry attempts This is the initial/minimum wait time before the first retry

func WithRootCertificateFromString

func WithRootCertificateFromString(pemContent string) ClientOption

WithRootCertificateFromString adds a custom root CA certificate from PEM string

func WithRootCertificates

func WithRootCertificates(pemFilePaths ...string) ClientOption

WithRootCertificates adds custom root CA certificates for server validation Useful for private CAs or self-signed certificates

func WithTLSClientConfig

func WithTLSClientConfig(tlsConfig *tls.Config) ClientOption

WithTLSClientConfig sets custom TLS configuration Use this for custom certificate validation, minimum TLS version, etc.

func WithTimeout

func WithTimeout(timeout time.Duration) ClientOption

WithTimeout sets a custom timeout for HTTP requests

func WithTracing

func WithTracing(config *OTelConfig) ClientOption

WithTracing enables OpenTelemetry tracing for all HTTP requests. This wraps the HTTP client transport with automatic instrumentation.

Example usage:

client, err := client.NewClient(apiKey, workspaceName,
    client.WithTracing(nil), // Uses default config with global tracer provider
)

Or with custom configuration:

otelConfig := &client.OTelConfig{
    TracerProvider: myTracerProvider,
    ServiceName:    "my-workbrew-client",
}
client, err := client.NewClient(apiKey, workspaceName,
    client.WithTracing(otelConfig),
)

The instrumentation automatically captures: - HTTP method, URL, status code - Request/response timing - Error details - All OpenTelemetry semantic conventions for HTTP

func WithTransport

func WithTransport(transport http.RoundTripper) ClientOption

WithTransport sets a custom HTTP transport (http.RoundTripper) Use this for advanced transport customization beyond TLS/proxy

func WithUserAgent

func WithUserAgent(userAgent string) ClientOption

WithUserAgent sets a custom user agent string

type OTelConfig

type OTelConfig struct {
	// TracerProvider is the OpenTelemetry tracer provider to use.
	// If nil, the global tracer provider will be used.
	TracerProvider trace.TracerProvider

	// Propagators is the propagator to use for context propagation.
	// If nil, the global propagator will be used.
	Propagators propagation.TextMapPropagator

	// ServiceName is the name of the service for tracing spans.
	// Defaults to "workbrew-client"
	ServiceName string

	// SpanNameFormatter allows customizing span names.
	// If nil, defaults to "HTTP {method}" format.
	SpanNameFormatter func(operation string, req *http.Request) string
}

OTelConfig holds OpenTelemetry configuration options

func DefaultOTelConfig

func DefaultOTelConfig() *OTelConfig

DefaultOTelConfig returns a default OpenTelemetry configuration

type QueryBuilder

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

QueryBuilder provides a fluent interface for building URL query parameters. It offers type-safe methods for adding parameters and handles empty value filtering automatically.

Example:

query := NewQueryBuilder().
    AddString("name", "workbrew").
    AddInt("limit", 100).
    AddBool("active", true).
    AddTime("created_after", time.Now().Add(-24*time.Hour))

params := query.Build()
// params = {"name": "workbrew", "limit": "100", "active": "true", "created_after": "2026-02-12T..."}

func NewQueryBuilder

func NewQueryBuilder() *QueryBuilder

NewQueryBuilder creates a new query builder instance with an empty parameter set.

Returns:

  • *QueryBuilder: A new query builder ready to accept parameters

Example:

qb := NewQueryBuilder()
qb.AddString("search", "homebrew").AddInt("page", 1)

func (*QueryBuilder) AddBool

func (qb *QueryBuilder) AddBool(key string, value bool) interfaces.QueryBuilder

AddBool adds a boolean parameter

func (*QueryBuilder) AddCustom

func (qb *QueryBuilder) AddCustom(key, value string) interfaces.QueryBuilder

AddCustom adds a custom parameter with any value

func (*QueryBuilder) AddIfNotEmpty

func (qb *QueryBuilder) AddIfNotEmpty(key, value string) interfaces.QueryBuilder

AddIfNotEmpty adds a parameter only if the value is not empty

func (*QueryBuilder) AddIfTrue

func (qb *QueryBuilder) AddIfTrue(condition bool, key, value string) interfaces.QueryBuilder

AddIfTrue adds a parameter only if the condition is true

func (*QueryBuilder) AddInt

func (qb *QueryBuilder) AddInt(key string, value int) interfaces.QueryBuilder

AddInt adds an integer parameter if the value is greater than 0

func (*QueryBuilder) AddInt64

func (qb *QueryBuilder) AddInt64(key string, value int64) interfaces.QueryBuilder

AddInt64 adds an int64 parameter if the value is greater than 0

func (*QueryBuilder) AddIntSlice

func (qb *QueryBuilder) AddIntSlice(key string, values []int) interfaces.QueryBuilder

AddIntSlice adds an integer slice parameter as comma-separated values

func (*QueryBuilder) AddString

func (qb *QueryBuilder) AddString(key, value string) interfaces.QueryBuilder

AddString adds a string parameter if the value is not empty

func (*QueryBuilder) AddStringSlice

func (qb *QueryBuilder) AddStringSlice(key string, values []string) interfaces.QueryBuilder

AddStringSlice adds a string slice parameter as comma-separated values

func (*QueryBuilder) AddTime

func (qb *QueryBuilder) AddTime(key string, value time.Time) interfaces.QueryBuilder

AddTime adds a time parameter in RFC3339 format if the time is not zero

func (*QueryBuilder) Build

func (qb *QueryBuilder) Build() map[string]string

Build returns a copy of the query parameters as a map. The returned map is a copy to prevent external modification of the builder's internal state.

Returns:

  • map[string]string: Copy of all query parameters

Example:

params := qb.AddString("name", "test").AddInt("limit", 50).Build()
// params = {"name": "test", "limit": "50"}

func (*QueryBuilder) BuildString

func (qb *QueryBuilder) BuildString() string

BuildString returns the query parameters as a URL-encoded string. Parameters are joined with "&" in key=value format.

Returns:

  • string: URL-encoded query string (e.g., "name=test&limit=50"), or empty string if no parameters

Example:

queryString := qb.AddString("name", "test").AddInt("page", 1).BuildString()
// queryString = "name=test&page=1"
url := baseURL + "?" + queryString

func (*QueryBuilder) Clear

func (qb *QueryBuilder) Clear() interfaces.QueryBuilder

Clear removes all parameters

func (*QueryBuilder) Count

func (qb *QueryBuilder) Count() int

Count returns the number of parameters

func (*QueryBuilder) Get

func (qb *QueryBuilder) Get(key string) string

Get retrieves a parameter value

func (*QueryBuilder) Has

func (qb *QueryBuilder) Has(key string) bool

Has checks if a parameter exists

func (*QueryBuilder) IsEmpty

func (qb *QueryBuilder) IsEmpty() bool

IsEmpty returns true if no parameters are set

func (*QueryBuilder) Merge

func (qb *QueryBuilder) Merge(other map[string]string) interfaces.QueryBuilder

Merge merges parameters from another query builder or map

func (*QueryBuilder) Remove

func (qb *QueryBuilder) Remove(key string) interfaces.QueryBuilder

Remove removes a parameter

type Transport

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

Transport represents the HTTP transport layer for Workbrew API. It provides methods for making HTTP requests to the Workbrew API with built-in authentication, retry logic, and request/response logging. This is an internal component - users should use workbrew.NewClient() instead.

func NewTransport

func NewTransport(apiKey string, workspaceName string, options ...ClientOption) (*Transport, error)

NewTransport creates a new Workbrew API transport with the provided API key and workspace. This is an internal function - users should use workbrew.NewClient() instead.

Parameters:

  • apiKey: Your Workbrew API key (required)
  • workspaceName: The name of the workspace to use (required)
  • options: Optional transport configuration options

Returns:

  • *Transport: Configured API transport instance
  • error: Any error encountered during transport creation

The transport is configured with:

  • Default timeout of 120 seconds
  • Automatic retry on transient failures (up to 3 retries)
  • Gzip compression support
  • Bearer token authentication
  • Production-ready logger (use WithLogger to customize)

func (*Transport) Delete

func (t *Transport) Delete(ctx context.Context, path string, queryParams map[string]string, headers map[string]string, result any) (*interfaces.Response, error)

Delete executes a DELETE request

func (*Transport) DeleteWithBody

func (t *Transport) DeleteWithBody(ctx context.Context, path string, body any, headers map[string]string, result any) (*interfaces.Response, error)

DeleteWithBody executes a DELETE request with body (for bulk operations)

func (*Transport) EnableTracing

func (t *Transport) EnableTracing(config *OTelConfig) error

EnableTracing wraps the HTTP client transport with OpenTelemetry instrumentation. This provides automatic tracing for all HTTP requests made by the client.

The instrumentation captures: - HTTP method, URL, status code - Request and response headers (configurable) - Error details - Request/response timing

All spans follow OpenTelemetry semantic conventions for HTTP clients.

func (*Transport) Get

func (t *Transport) Get(ctx context.Context, path string, queryParams map[string]string, headers map[string]string, result any) (*interfaces.Response, error)

Get executes a GET request

func (*Transport) GetBytes

func (t *Transport) GetBytes(ctx context.Context, path string, queryParams map[string]string, headers map[string]string) (*interfaces.Response, []byte, error)

GetBytes performs a GET request and returns raw bytes without unmarshaling Use this for non-JSON responses like CSV, HTML, binary files, etc.

func (*Transport) GetHTTPClient

func (t *Transport) GetHTTPClient() *resty.Client

GetHTTPClient returns the underlying resty HTTP client. Use this to access advanced resty features or customize the HTTP client directly.

Returns:

  • *resty.Client: The underlying resty client instance

func (*Transport) GetLogger

func (t *Transport) GetLogger() *zap.Logger

GetLogger returns the configured zap logger instance. Use this to add custom logging within your application using the same logger.

Returns:

  • *zap.Logger: The configured logger instance

func (*Transport) Patch

func (t *Transport) Patch(ctx context.Context, path string, body any, headers map[string]string, result any) (*interfaces.Response, error)

Patch executes a PATCH request

func (*Transport) Post

func (t *Transport) Post(ctx context.Context, path string, body any, headers map[string]string, result any) (*interfaces.Response, error)

Post executes a POST request with JSON body

func (*Transport) PostForm

func (t *Transport) PostForm(ctx context.Context, path string, formData map[string]string, headers map[string]string, result any) (*interfaces.Response, error)

PostForm executes a POST request with form-urlencoded data

func (*Transport) PostMultipart

func (t *Transport) PostMultipart(ctx context.Context, path string, fileField string, fileName string, fileReader io.Reader, fileSize int64, formFields map[string]string, headers map[string]string, progressCallback interfaces.MultipartProgressCallback, result any) (*interfaces.Response, error)

PostMultipart executes a POST request with multipart form data and progress tracking

func (*Transport) PostWithQuery

func (t *Transport) PostWithQuery(ctx context.Context, path string, queryParams map[string]string, body any, headers map[string]string, result any) (*interfaces.Response, error)

PostWithQuery executes a POST request with both body and query parameters

func (*Transport) Put

func (t *Transport) Put(ctx context.Context, path string, body any, headers map[string]string, result any) (*interfaces.Response, error)

Put executes a PUT request

func (*Transport) QueryBuilder

func (t *Transport) QueryBuilder() interfaces.ServiceQueryBuilder

QueryBuilder creates a new query builder instance for constructing URL query parameters. The query builder provides a fluent interface for adding parameters with type safety.

Returns:

  • interfaces.ServiceQueryBuilder: A new query builder instance

Example:

params := transport.QueryBuilder().
    AddString("name", "test").
    AddInt("limit", 100).
    AddBool("active", true).
    Build()

func (*Transport) SetWorkspace

func (t *Transport) SetWorkspace(workspaceName string)

SetWorkspace changes the active workspace for all subsequent API calls. This updates the base URL to target the specified workspace.

Parameters:

  • workspaceName: The name of the workspace to switch to

Example:

transport.SetWorkspace("production-workspace")

Jump to

Keyboard shortcuts

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