Skip to content
🦅 Developer-friendly, Real-World-ready and extensible HTTP client for Go
Go
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github/workflows
benchmark
hxutil
pb
retry
.golangci.yml
LICENSE
README.md
body_test.go
client.go
client_test.go
codecov.yml
config.go
config_go1.12.go
config_go1.13.go
example_test.go
go.mod
helper.go
helper_test.go
option.go
option_test.go
request_handler.go
response_handler.go
response_handler_test.go
version.go

README.md

hx

CI GoDoc codecov License

Developer-friendly, Production-ready and extensible HTTP client for Go

Features

...

Plugins

  • retry
  • pb - Marshaling and Unmarshaling protocol buffers

Examples

Simple GET

type Content struct {
	Body string `json:"body"`
}

var cont Content

ctx := context.Background()
err := hx.Get(ctx, "https://api.example.com/contents/1",
	hx.WhenSuccess(hx.AsJSON(&cont)),
	hx.WhenFailure(hx.AsError()),
)

Real-world

func init() {
	defaultTransport := hxutil.CloneTransport(http.DefaultTransport.(*http.Transport))

	// Tweak keep-alive configuration
	defaultTransport.MaxIdleConns = 500
	defaultTransport.MaxIdleConnsPerHost = 100

	// Set global options
	hx.DefaultOptions = append(
		hx.DefaultOptions,
		hx.UserAgent(fmt.Sprintf("yourapp (%s)", hx.DefaultUserAgent)),
		hx.Transport(defaultTransport),
		hx.TransportFrom(func(rt http.RoundTripper) http.RoundTripper {
			return &ochttp.Transport{Base: rt}
		}),
	)
}

func NewContentAPI() *hx.Client {
	// Set common options for API ciient
	return &ContentAPI{
		client: hx.NewClient(
			hx.BaseURL("https://api.example.com"),
		),
	}
}

type ContentAPI struct {
	client *hx.Client
}

func (a *ContentAPI) GetContent(ctx context.Context, id int) (*Content, error) {
	var cont Content

	err := a.client.Get(ctx, hx.Path("api", "contents", id),
		hx.WhenSuccess(hx.AsJSON(&cont)),
		hx.WhenFailure(hx.AsError()),
	)

	if err != nil {
		// ...
	}

	return &cont, nil
}

func (a *ContentAPI) CreateContent(ctx context.Context, in *Content) (*Content, error) {
	var out Content

	err := a.client.Post(ctx, "/api/contents",
		hx.JSON(in),
		hx.WhenSuccess(hx.AsJSON(&out)),
		hx.WhenStatus(hx.AsJSONError(&InvalidArgument{}), http.StatusBadRequest),
		hx.WhenFailure(hx.AsError()),
	)

	if err != nil {
		var (
			invalidArgErr *InvalidArgument
			respErr       *hx.ResponseError
		)
		if errors.As(err, &invalidArgErr) {
			// handle known error
		} else if errors.As(err, &respErr) {
			// handle unknown response error
		} else {
			err := errors.Unwrap(err)
			// handle unknown error
		}
	}

	return &out, nil
}
You can’t perform that action at this time.