ghttp

package module
v0.0.0-...-03e1aea Latest Latest
Warning

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

Go to latest
Published: Aug 29, 2025 License: MIT Imports: 24 Imported by: 3

README

ghttp

A Go HTTP client designed for quick integration with REST APIs.

Installation

go get github.com/nexuer/ghttp

Usage

Options
Configure the HTTP roundTripper

WithTransport(trans http.RoundTripper)

// Example: Configure proxy and client certificates
ghttp.WithTransport(&http.Transport{
    Proxy: ghttp.ProxyURL(":7890"), // or http.ProxyFromEnvironment
    TLSClientConfig: &tls.Config{
        InsecureSkipVerify: true,
    },
}),
Set Default Timeout

WithTimeout(d time.Duration)

// Example: Set a specific timeout
ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
defer cancel()
_, err := client.Invoke(ctx, http.MethodGet, "/api/v4/projects", nil, nil)
Set Default User-Agent

WithUserAgent(userAgent string)

Set Default Endpoint

WithEndpoint(endpoint string)

Set Default Content-Type

WithContentType(contentType string)

Configure Proxy

Default: http.ProxyFromEnvironment, can use ghttp.ProxyURL(url)

WithProxy(f func(*http.Request) (*url.URL, error))

Bind Struct for Non-2xx Status Codes

WithNot2xxError(f func() error)

Enable Debugging

WithDebug(open bool)

Set Limiter

WithLimiter(l Limiter)

Invocation Methods
  • Invoke(ctx context.Context, method, path string, args any, reply any, opts ...CallOption) (*http.Response, error)
  • Do(req *http.Request, opts ...CallOption) (*http.Response, error)

CallOption is an interface that allows customization through method implementation:

type CallOption interface {
    Before(request *http.Request) error
    After(response *http.Response) error
}
Binding
Request Query

usage

Encoding

Automatically loads the corresponding Codec instance based on content-type. Subtype extraction occurs (e.g., both application/json and application/vnd.api+json are treated as json).

Custom Codec Override default JSON serialization using sonic:

package main

import (
    "github.com/bytedance/sonic"
    "github.com/nexuer/ghttp"
)

type codec struct{}

func (codec) Name() string {
    return "sonic-json"
}

func (codec) Marshal(v interface{}) ([]byte, error) {
    return sonic.Marshal(v)
}

func (codec) Unmarshal(data []byte, v interface{}) error {
    return sonic.Unmarshal(data, v)
}

func main() {
    ghttp.RegisterCodec("application/json", codec{})
}
Debugging

Enable debugging with WithDebug, output example:

--------------------------------------------
Trace                         Value                          
--------------------------------------------
DNSDuration                   3.955292ms                    
ConnectDuration               102.718541ms                  
TLSHandshakeDuration          98.159333ms                   
RequestDuration               138.834µs                     
WaitResponseDuration          307.559875ms                  
TotalDuration                 412.40375ms                   

* Host gitlab.com:443 was resolved.
* IPv4: 198.18.7.159
*   Trying 198.18.7.159:443...
* Connected to gitlab.com (198.18.7.159) port 443
* SSL connection using TLS 1.3 / TLS_AES_128_GCM_SHA256
* ALPN: server accepted h2
* using HTTP/1.1
> POST /oauth/token HTTP/1.1
> User-Agent: sdk/gitlab-v0.0.1
> Accept: application/json
> Content-Type: application/json
> Beforehook: BeforeHook
> Authorization: Basic Z2l0bGFiOnBhc3N3b3Jk
>

{
    "client_id": "app",
    "grant_type": "password"
}

> HTTP/2.0 401 Unauthorized
... (remaining output truncated for brevity)

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BindResponseBody

func BindResponseBody(resp *http.Response, target any) error

BindResponseBody binds the body of an HTTP response to the given 'target' struct, automatically decoding the body based on the Content-Type header of the response.

This function checks the Content-Type header and decodes the response body into the corresponding Go type. It assumes that the 'target' parameter is a pointer to the structure that should be populated with the response data.

Example usage:

var userResponse User
err := BindResponseBody(response, &userResponse)
if err != nil {
    log.Fatal("Failed to bind response body:", err)
}
// The 'userResponse' struct will now be populated with the decoded response data.

func CodecForRequest

func CodecForRequest(r *http.Request, name ...string) (encoding.Codec, bool)

CodecForRequest get encoding.Codec via http.Request

func CodecForResponse

func CodecForResponse(r *http.Response, name ...string) (encoding.Codec, bool)

CodecForResponse get encoding.Codec via http.Response

func CodecForString

func CodecForString(contentType string) encoding.Codec

CodecForString get encoding.Codec via string

func EncodeRequestBody

func EncodeRequestBody(req *http.Request, body any) error

EncodeRequestBody encodes the provided body content based on the Content-Type of the given HTTP request, and sets the encoded body in the request.

The function will automatically detect the Content-Type header of the request and encode the body accordingly (e.g., JSON, XML, etc.). It then uses SetRequestBody to set the encoded body in the request.

Example usage:

// Example structure to be encoded into the request body
type MyRequest struct {
    Name  string `json:"name"`
    Value int    `json:"value"`
}

req, err := http.NewRequest("POST", "https://example.com/api", nil)
if err != nil {
    log.Fatal("Failed to create request:", err)
}

body := MyRequest{Name: "example", Value: 42}
err = EncodeRequestBody(req, body)
if err != nil {
    log.Fatal("Failed to encode request body:", err)
}

// Now the request body is set to the JSON-encoded version of MyRequest
fmt.Println("Request prepared with body:", req.Body)

func ForceHttps

func ForceHttps(endpoint string) string

ForceHttps ensures that the provided endpoint is using the HTTPS protocol. It checks if the URL already contains a scheme (like "http://"), removes it, and then prepends "https://" to the endpoint to ensure the URL uses HTTPS.

Example usage:

url := "http://example.com"
secureUrl := ForceHttps(url)
fmt.Println(secureUrl) // Output: "https://example.com"

func IsTimeout

func IsTimeout(err error) bool

func ProxyURL

func ProxyURL(address string) func(*http.Request) (*url.URL, error)

ProxyURL returns a function that sets a proxy URL for the given HTTP request.

This function accepts an address as input and ensures that the address is properly formatted as a valid URL. If the address is a relative address (e.g., ":7890" or "/proxy"), it is converted to a full HTTP address (e.g., "http://127.0.0.1:7890"). If the address does not include a scheme (e.g., "http://"), the function prepends "http://" to the address. The returned function can be used to configure HTTP requests to route through the specified proxy.

func RegisterCodec

func RegisterCodec(contentType string, codec encoding.Codec)

func RegisterCodecName

func RegisterCodecName(contentType string, name string)

func SetQuery

func SetQuery(req *http.Request, q any) error

SetQuery encodes the provided query parameters into a URL query string and appends them to the given HTTP request's URL. This function uses the `github.com/nexuer/ghttp/query` package to encode the query parameters. The query parameters are serialized into the URL query string format and appended to the existing URL of the HTTP request. If the request already contains a query string, the new parameters will be appended to it. If no query parameters are provided, no changes are made to the request.

Example usage:

req, err := http.NewRequest("GET", "https://example.com/api", nil)
if err != nil {
    log.Fatal("Failed to create request:", err)
}

// Define query parameters as a struct
queryParams := struct {
    Name  string `query:"name"`
    Value int    `query:"value"`
}{
    Name:  "example",
    Value: 42,
}

err = SetQuery(req, queryParams)
if err != nil {
    log.Fatal("Failed to set query parameters:", err)
}

// The request URL will now include the query parameters encoded as `?name=example&value=42`

func SetRequestBody

func SetRequestBody(req *http.Request, body io.Reader) error

SetRequestBody modifies the body of the given HTTP request.

This function allows you to set or replace the body of the HTTP request with the provided 'body' parameter. The body is expected to be an io.Reader, which means it can be any type that implements the io.Reader interface, such as a byte buffer or a file stream.

Example usage:

req, err := http.NewRequest("POST", "https://example.com", nil)
if err != nil {
    log.Fatal("Failed to create request:", err)
}

body := strings.NewReader("some request data")
err = SetRequestBody(req, body)
if err != nil {
    log.Fatal("Failed to set request body:", err)
}
// Now the request body is set to "some request data"

func StatusForErr

func StatusForErr(err error) (int, bool)

Types

type CallOption

type CallOption interface {
	Before(request *http.Request) error
	After(response *http.Response) error
}

func After

func After(hooks ...ResponseFunc) CallOption

func BasicAuth

func BasicAuth(username, password string) CallOption

func BearerToken

func BearerToken(token string) CallOption

func Before

func Before(hooks ...RequestFunc) CallOption

func Query

func Query(q any) CallOption

type CallOptions

type CallOptions struct {
	// Set query parameters
	Query any

	// Basic auth
	Username string
	Password string

	// Bearer token
	BearerToken string

	// hooks
	BeforeHooks []RequestFunc
	AfterHooks  []ResponseFunc
}

CallOptions default call options

func (*CallOptions) After

func (c *CallOptions) After(response *http.Response) error

func (*CallOptions) Before

func (c *CallOptions) Before(request *http.Request) error

type Client

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

Client is an HTTP client.

func NewClient

func NewClient(opts ...ClientOption) *Client

func (*Client) Do

func (c *Client) Do(req *http.Request, opts ...CallOption) (*http.Response, error)

Do send an HTTP request and decodes the body of response into target.

func (*Client) Invoke

func (c *Client) Invoke(ctx context.Context, method, path string, args any, reply any, opts ...CallOption) (*http.Response, error)

func (*Client) SetEndpoint

func (c *Client) SetEndpoint(endpoint string)

type ClientOption

type ClientOption func(*clientOptions)

ClientOption is HTTP client option.

func WithContentType

func WithContentType(contentType string) ClientOption

WithContentType with client request content type.

func WithDebug

func WithDebug(open bool) ClientOption

WithDebug open debug.

func WithDebugInterface

func WithDebugInterface(f func() DebugInterface) ClientOption

WithDebugInterface sets the function to create a new DebugInterface instance.

func WithEndpoint

func WithEndpoint(endpoint string) ClientOption

WithEndpoint with client addr.

func WithLimiter

func WithLimiter(l Limiter) ClientOption

WithLimiter sets a rate limiter for the client. This limiter will be applied to control the number of requests made to the server, ensuring that the requests stay within the specified limits.

func WithNot2xxError

func WithNot2xxError(f func() error) ClientOption

WithNot2xxError handle response status code < 200 and code > 299

func WithProxy

func WithProxy(f func(*http.Request) (*url.URL, error)) ClientOption

WithProxy with proxy url.

func WithTLSConfig

func WithTLSConfig(cfg *tls.Config) ClientOption

WithTLSConfig with tls config.

func WithTimeout

func WithTimeout(timeout time.Duration) ClientOption

WithTimeout with client request timeout.

func WithTransport

func WithTransport(transport http.RoundTripper) ClientOption

WithTransport with http.RoundTrippe.

func WithUserAgent

func WithUserAgent(userAgent string) ClientOption

WithUserAgent with client user agent.

type Debug

type Debug struct {
	Writer        io.Writer
	Trace         bool
	TraceCallback func(w io.Writer, info TraceInfo)
	// contains filtered or unexported fields
}

func (*Debug) After

func (d *Debug) After(request *http.Request, response *http.Response, err error)

func (*Debug) Before

func (d *Debug) Before(req *http.Request)

type DebugInterface

type DebugInterface interface {
	Before(request *http.Request)
	After(request *http.Request, response *http.Response, err error)
}

type Error

type Error struct {
	URL        *url.URL
	Method     string
	StatusCode int
	Err        error
}

func (Error) Error

func (e Error) Error() string

func (Error) Unwrap

func (e Error) Unwrap() error

type Limiter

type Limiter interface {
	Wait(ctx context.Context) error
}

type RequestFunc

type RequestFunc func(request *http.Request) error

type ResponseFunc

type ResponseFunc func(response *http.Response) error

type TraceInfo

type TraceInfo struct {
	DNSDuration          time.Duration `json:"DNSDuration,omitempty" yaml:"DNSDuration" xml:"DNSDuration"`
	ConnectDuration      time.Duration `json:"connectDuration,omitempty" yaml:"connectDuration" xml:"connectDuration"`
	TLSHandshakeDuration time.Duration `json:"TLSHandshakeDuration,omitempty" yaml:"TLSHandshakeDuration" xml:"TLSHandshakeDuration"`
	RequestDuration      time.Duration `json:"requestDuration,omitempty" yaml:"requestDuration" xml:"requestDuration"`
	WaitResponseDuration time.Duration `json:"waitResponseDuration,omitempty" yaml:"waitResponseDuration" xml:"waitResponseDuration"`
	ResponseDuration     time.Duration `json:"responseDuration,omitempty" yaml:"responseDuration" xml:"responseDuration"`
	TotalDuration        time.Duration `json:"totalDuration,omitempty" yaml:"totalDuration" xml:"totalDuration"`
	// contains filtered or unexported fields
}

func (TraceInfo) Context

func (t TraceInfo) Context() context.Context

func (TraceInfo) String

func (t TraceInfo) String() string

func (TraceInfo) Table

func (t TraceInfo) Table() []byte

Directories

Path Synopsis
xml

Jump to

Keyboard shortcuts

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