mclient

package
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Sep 28, 2025 License: MIT Imports: 28 Imported by: 0

Documentation

Overview

Example

Example demonstrates basic usage of the client. This is a runnable example, but it will not make a real network call as the URL is a placeholder. To make it a "godoc" example, we'd typically mock the server.

package main

import (
	"fmt"

	"github.com/graingo/maltose/net/mclient"
)

func main() {
	client := mclient.New()

	// In a real scenario, you would handle the response and error.
	_, err := client.R().
		SetHeader("Accept", "application/json").
		Get("https://api.example.com/users")

	if err != nil {
		// This will likely print an error in a test environment, which is expected.
		fmt.Println("Request intended to fail for example purposes.")
	}
}
Output:

Request intended to fail for example purposes.
Example (CustomRetryCondition)

Example_customRetryCondition demonstrates custom retry conditions.

package main

import (
	"fmt"
	"net/http"

	"github.com/graingo/maltose/net/mclient"
)

func main() {
	client := mclient.New()

	// Define custom retry condition
	customRetryCondition := func(resp *http.Response, err error) bool {
		// Retry on network errors
		if err != nil {
			return true
		}
		// Retry on server errors (5xx) or rate limiting (429)
		if resp != nil && (resp.StatusCode >= 500 || resp.StatusCode == 429) {
			return true
		}
		return false
	}

	config := mclient.RetryConfig{Count: 3}

	_, err := client.R().
		SetRetry(config).
		SetRetryCondition(customRetryCondition).
		Get("https://api.example.com/users")

	if err != nil {
		fmt.Println("Custom retry example finished.")
	}
}
Output:

Custom retry example finished.
Example (JSON)

Example_jSON demonstrates JSON request and response handling.

package main

import (
	"fmt"

	"github.com/graingo/maltose/net/mclient"
)

func main() {
	client := mclient.New()

	// Define request and response structures
	type User struct {
		Name  string `json:"name"`
		Email string `json:"email"`
	}

	type CreateResponse struct {
		ID     int    `json:"id"`
		Name   string `json:"name"`
		Status string `json:"status"`
	}

	// Prepare request data
	user := User{
		Name:  "John Doe",
		Email: "john@example.com",
	}

	// Prepare result container
	var result CreateResponse

	// Send request (this will fail as the URL is not real)
	_, err := client.R().
		SetBody(user).
		SetResult(&result).
		Post("https://api.example.com/users")

	if err != nil {
		fmt.Println("JSON request example finished.")
	}

	// In a real case, you might print the result:
	// fmt.Printf("Created user: %s (ID: %d)\n", result.Name, result.ID)

}
Output:

JSON request example finished.
Example (Middleware)

Example_middleware demonstrates middleware usage.

package main

import (
	"fmt"
	"log"

	"github.com/graingo/maltose/net/mclient"
)

func main() {
	client := mclient.New()

	// Add auth middleware
	client.Use(mclient.MiddlewareFunc(func(next mclient.HandlerFunc) mclient.HandlerFunc {
		return func(req *mclient.Request) (*mclient.Response, error) {
			req.SetHeader("Authorization", "Bearer test-token")
			return next(req)
		}
	}))

	// Add logging middleware
	client.Use(mclient.MiddlewareFunc(func(next mclient.HandlerFunc) mclient.HandlerFunc {
		return func(req *mclient.Request) (*mclient.Response, error) {
			log.Printf("Sending request to %s", req.Request.URL.String())
			resp, err := next(req)
			if err != nil {
				log.Printf("Request failed: %v", err)
			}
			return resp, err
		}
	}))

	_, err := client.R().Get("https://api.example.com/users")

	if err != nil {
		fmt.Println("Middleware example finished.")
	}
}
Output:

Middleware example finished.
Example (Retry)

Example_retry demonstrates retry mechanism.

package main

import (
	"fmt"
	"time"

	"github.com/graingo/maltose/net/mclient"
)

func main() {
	client := mclient.New()

	// Configure retry strategy
	config := mclient.RetryConfig{
		Count:         3,
		BaseInterval:  time.Second,
		MaxInterval:   30 * time.Second,
		BackoffFactor: 2.0,
		JitterFactor:  0.1,
	}

	// Send request with retry (this will fail as the URL is not real)
	_, err := client.R().
		SetRetry(config).
		Get("https://api.example.com/users")

	if err != nil {
		fmt.Println("Retry example finished.")
	}

}
Output:

Retry example finished.

Index

Examples

Constants

This section is empty.

Variables

View Source
var LogMaxBodySize = -1

Functions

This section is empty.

Types

type Client

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

Client is an HTTP client with enhanced features.

func New

func New() *Client

New creates and returns a new HTTP client object. It comes with a set of default internal middlewares for recovery, tracing, and metrics.

func NewWithConfig

func NewWithConfig(config ClientConfig) *Client

NewWithConfig creates and returns a client with given config. Note that the internal middlewares (recovery, trace, metric) are still applied.

func (*Client) Clone

func (c *Client) Clone() *Client

Clone creates and returns a copy of the current client.

func (*Client) GetClient

func (c *Client) GetClient() *http.Client

GetClient returns the underlying http.Client.

func (*Client) NewRequest

func (c *Client) NewRequest() *Request

NewRequest creates and returns a new request object.

func (*Client) R

func (c *Client) R() *Request

R returns a new request object bound to this client for chain calls.

func (*Client) SetAgent

func (c *Client) SetAgent(agent string) *Client

SetAgent sets the User-Agent header for client.

func (*Client) SetBaseURL

func (c *Client) SetBaseURL(baseURL string) *Client

SetBaseURL sets the base URL for all requests.

func (*Client) SetBasicAuth

func (c *Client) SetBasicAuth(username, password string) *Client

SetBasicAuth sets HTTP basic authentication for the client.

func (*Client) SetBrowserMode

func (c *Client) SetBrowserMode(enabled bool) *Client

SetBrowserMode enables browser mode of the client. When browser mode is enabled, it automatically saves and sends cookie content from and to server via an in-memory cookie jar.

func (*Client) SetConfig

func (c *Client) SetConfig(config ClientConfig) *Client

SetConfig sets the client configuration.

func (*Client) SetContentType

func (c *Client) SetContentType(contentType string) *Client

SetContentType sets HTTP content type for the client.

func (*Client) SetCookie

func (c *Client) SetCookie(key, value string) *Client

SetCookie sets a cookie pair for the client.

func (*Client) SetCookieMap

func (c *Client) SetCookieMap(m map[string]string) *Client

SetCookieMap sets cookie items with map.

func (*Client) SetHeader

func (c *Client) SetHeader(key, value string) *Client

SetHeader sets a custom HTTP header pair for the client.

func (*Client) SetHeaderMap

func (c *Client) SetHeaderMap(m map[string]string) *Client

SetHeaderMap sets custom HTTP headers with map.

func (*Client) SetRedirectLimit

func (c *Client) SetRedirectLimit(redirectLimit int) *Client

SetRedirectLimit limits the number of jumps for redirection. It sets the CheckRedirect function on the underlying http.Client. A limit of 0 means no redirects will be followed.

func (*Client) SetTLSConfig

func (c *Client) SetTLSConfig(tlsConfig *tls.Config) error

SetTLSConfig sets the client's TLS configuration.

func (*Client) SetTLSKeyCrt

func (c *Client) SetTLSKeyCrt(crtFile, keyFile string) error

SetTLSKeyCrt sets client TLS certificate and key files.

func (*Client) SetTimeout

func (c *Client) SetTimeout(t time.Duration) *Client

SetTimeout sets the request timeout for the client.

func (*Client) SetTransport

func (c *Client) SetTransport(transport http.RoundTripper) *Client

SetTransport sets the client transport.

func (*Client) Use

func (c *Client) Use(middlewares ...MiddlewareFunc) *Client

Use adds middleware handlers to the client.

func (*Client) WithGlobalRateLimit

func (c *Client) WithGlobalRateLimit(rps float64, burst int) *Client

WithGlobalRateLimit applies rate limiting to all requests from this client.

type ClientConfig

type ClientConfig struct {
	// BaseURL specifies the base URL for all requests.
	BaseURL string `mconv:"base_url"`
	// Timeout specifies a time limit for requests made by this client.
	Timeout time.Duration `mconv:"timeout"`
	// Transport specifies the mechanism by which individual HTTP requests are made.
	Transport http.RoundTripper
	// Header specifies the default header for requests.
	Header http.Header
}

ClientConfig is the configuration for Client.

type HandlerFunc

type HandlerFunc func(*Request) (*Response, error)

HandlerFunc defines the handler used by middleware.

type MiddlewareFunc

type MiddlewareFunc func(HandlerFunc) HandlerFunc

MiddlewareFunc is the function type for middleware.

func MiddlewareLog

func MiddlewareLog(logger *mlog.Logger) MiddlewareFunc

MiddlewareLog creates a middleware that logs request and response details in two steps: 1. Before the request is sent ("started"). 2. After the request is completed ("finished" or "error"). This allows for better observability, especially for hanging requests.

func MiddlewareRateLimit

func MiddlewareRateLimit(config RateLimitConfig) MiddlewareFunc

MiddlewareRateLimit returns a middleware that limits the rate of requests.

type RateLimitConfig

type RateLimitConfig struct {
	// RequestsPerSecond is the number of requests allowed per second
	RequestsPerSecond float64
	// Burst is the maximum number of requests allowed to happen at once
	Burst int
	// Skip determines if rate limiting should be skipped for a request
	Skip func(*Request) bool
	// ErrorHandler handles rate limit errors
	ErrorHandler func(context.Context, error) (*Response, error)
}

RateLimitConfig represents options for rate limiting middleware.

type RateLimiter

type RateLimiter interface {
	// Wait blocks until a request can be allowed or context is cancelled.
	Wait(ctx context.Context) error
	// TryAcquire tries to acquire a token without blocking.
	TryAcquire() bool
}

RateLimiter defines the interface for rate limiters.

type Request

type Request struct {
	*http.Request // Request is the underlying http.Request object.
	// contains filtered or unexported fields
}

Request is the struct for client request.

func (*Request) ContentType

func (r *Request) ContentType(contentType string) *Request

ContentType sets the Content-Type header for the request.

func (*Request) Delete added in v0.1.2

func (r *Request) Delete(url string) (*Response, error)

Delete sets the method to DELETE and executes the request.

func (*Request) Do deprecated

func (r *Request) Do() (*Response, error)

Do executes the request.

Deprecated: This method is deprecated and will be removed in a future version. Please use the HTTP method-specific functions like Get, Post, etc., instead. For example, instead of `req.Method("GET").Do()`, use `req.Get(url)`.

func (*Request) Get added in v0.1.2

func (r *Request) Get(url string) (*Response, error)

Get sets the method to GET and executes the request.

func (*Request) GetRequest

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

GetRequest returns the *http.Request object.

func (*Request) GetResponse

func (r *Request) GetResponse() *Response

GetResponse returns the response object of this request.

func (*Request) Head added in v0.1.2

func (r *Request) Head(url string) (*Response, error)

Head sets the method to HEAD and executes the request.

func (*Request) Method

func (r *Request) Method(method string) *Request

Method sets the HTTP method for the request.

func (*Request) Options added in v0.1.2

func (r *Request) Options(url string) (*Response, error)

Options sets the method to OPTIONS and executes the request.

func (*Request) Patch added in v0.1.2

func (r *Request) Patch(url string) (*Response, error)

Patch sets the method to PATCH and executes the request.

func (*Request) Post added in v0.1.2

func (r *Request) Post(url string) (*Response, error)

Post sets the method to POST and executes the request.

func (*Request) Put added in v0.1.2

func (r *Request) Put(url string) (*Response, error)

Put sets the method to PUT and executes the request.

func (*Request) Send

func (r *Request) Send(url string) (*Response, error)

Send performs a request with the chain style API. If the method is not specified, it defaults to GET.

func (*Request) SetBody

func (r *Request) SetBody(body any) *Request

SetBody sets the request body.

func (*Request) SetContext

func (r *Request) SetContext(ctx context.Context) *Request

SetContext sets the context for the request. It creates a new underlying http.Request with the given context.

func (*Request) SetError

func (r *Request) SetError(err any) *Request

SetError sets the error result object for error response.

func (*Request) SetForm

func (r *Request) SetForm(key, value string) *Request

SetForm sets a form parameter for the request.

func (*Request) SetFormMap

func (r *Request) SetFormMap(params map[string]string) *Request

SetFormMap sets multiple form parameters from a map.

func (*Request) SetHeader

func (r *Request) SetHeader(key, value string) *Request

SetHeader sets a header key-value pair for the request. This is an alias of Header method for better chain API compatibility.

func (*Request) SetHeaders

func (r *Request) SetHeaders(headers map[string]string) *Request

SetHeaders sets multiple headers at once.

func (*Request) SetQuery

func (r *Request) SetQuery(key, value string) *Request

SetQuery sets a query parameter for the request.

func (*Request) SetQueryMap

func (r *Request) SetQueryMap(params map[string]string) *Request

SetQueryMap sets multiple query parameters from a map.

func (*Request) SetResponse

func (r *Request) SetResponse(resp *Response)

SetResponse sets the response object for this request.

func (*Request) SetResult

func (r *Request) SetResult(result any) *Request

SetResult sets the result object for successful response.

func (*Request) SetRetry

func (r *Request) SetRetry(config RetryConfig) *Request

SetRetry sets retry configuration.

func (*Request) SetRetryCondition

func (r *Request) SetRetryCondition(condition func(*http.Response, error) bool) *Request

SetRetryCondition sets a custom retry condition function. The function takes the HTTP response and error as input and returns true if the request should be retried.

func (*Request) SetRetrySimple

func (r *Request) SetRetrySimple(count int, baseInterval time.Duration) *Request

SetRetrySimple sets retry count and base interval with default backoff and jitter.

func (*Request) URL

func (r *Request) URL(url string) *Request

URL sets the request URL.

func (*Request) Use

func (r *Request) Use(middlewares ...MiddlewareFunc) *Request

Use adds middleware handlers to the request.

type Response

type Response struct {
	*http.Response // Response is the underlying http.Response object of certain request.
	// contains filtered or unexported fields
}

Response is the struct for client request response.

func (*Response) Close

func (r *Response) Close() error

Close closes the response when it will never be used.

func (*Response) GetCookie

func (r *Response) GetCookie(key string) string

GetCookie retrieves and returns the cookie value of specified `key`.

func (*Response) GetCookieMap

func (r *Response) GetCookieMap() map[string]string

GetCookieMap retrieves and returns a copy of current cookie values map.

func (*Response) GetCookies

func (r *Response) GetCookies() map[string]string

GetCookies retrieves and returns all cookie values.

func (*Response) GetError

func (r *Response) GetError() any

GetError returns the error result object.

func (*Response) GetResult

func (r *Response) GetResult() any

GetResult returns the result object.

func (*Response) IsSuccess

func (r *Response) IsSuccess() bool

IsSuccess returns whether the response status code is in the 2xx range, indicating that the request was successfully received, understood, and accepted.

func (*Response) Parse

func (r *Response) Parse(result interface{}) error

Parse parses the response body into the given result.

func (*Response) ReadAll

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

ReadAll retrieves and returns the response content as []byte.

func (*Response) ReadAllString

func (r *Response) ReadAllString() string

ReadAllString retrieves and returns the response content as string.

func (*Response) SetBodyContent

func (r *Response) SetBodyContent(content []byte)

SetBodyContent overwrites response content with custom one.

func (*Response) SetError

func (r *Response) SetError(err interface{})

SetError sets the error result object for error response.

func (*Response) SetResult

func (r *Response) SetResult(result interface{})

SetResult sets the result object for successful response.

type RetryConfig

type RetryConfig struct {
	// Count is the maximum number of retries.
	// For example, if Count is 3, the request will be tried up to 4 times (initial attempt + 3 retries).
	Count int

	// BaseInterval is the base interval between retries.
	// This is the starting point for calculating the delay between retries.
	// For example, if BaseInterval is 1 second, the first retry will wait at least 1 second.
	BaseInterval time.Duration

	// MaxInterval is the maximum interval between retries.
	// This prevents the delay from growing too large due to exponential backoff.
	// For example, if MaxInterval is 30 seconds, even if the calculated delay is 60 seconds,
	// the actual delay will be capped at 30 seconds.
	MaxInterval time.Duration

	// BackoffFactor is the factor for exponential backoff.
	// Each retry's delay is calculated by multiplying the previous delay by this factor.
	// For example, if BaseInterval is 1 second and BackoffFactor is 2.0:
	// - First retry: 1 second
	// - Second retry: 2 seconds
	// - Third retry: 4 seconds
	// - And so on...
	BackoffFactor float64

	// JitterFactor is the factor for random jitter.
	// This adds randomness to the delay to prevent multiple clients from retrying simultaneously.
	// The actual jitter is calculated as: delay * JitterFactor * (random number between -1 and 1)
	// For example, if the calculated delay is 1 second and JitterFactor is 0.1:
	// - The actual delay will be between 0.9 and 1.1 seconds
	// A value of 0 means no jitter will be added.
	JitterFactor float64
}

RetryConfig is the configuration for request retry.

func DefaultRetryConfig

func DefaultRetryConfig() RetryConfig

DefaultRetryConfig returns the default retry configuration. The default values are: - Count: 3 retries - BaseInterval: 1 second - MaxInterval: 30 seconds - BackoffFactor: 2.0 (doubles the delay each time) - JitterFactor: 0.1 (adds ±10% random jitter)

type TokenBucketLimiter

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

TokenBucketLimiter implements a token bucket rate limiter.

func NewTokenBucketLimiter

func NewTokenBucketLimiter(rate float64, bucketSize int) *TokenBucketLimiter

NewTokenBucketLimiter creates a new token bucket rate limiter. The rate is specified in requests per second, and bucketSize determines the maximum burst size.

func (*TokenBucketLimiter) TryAcquire

func (l *TokenBucketLimiter) TryAcquire() bool

TryAcquire attempts to take a token from the bucket without blocking. Returns true if a token was successfully taken, false otherwise.

func (*TokenBucketLimiter) Wait

func (l *TokenBucketLimiter) Wait(ctx context.Context) error

Wait blocks until a token is available or the context is cancelled.

Jump to

Keyboard shortcuts

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