httpclient

package module
v0.0.7 Latest Latest
Warning

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

Go to latest
Published: Dec 5, 2023 License: MIT Imports: 18 Imported by: 0

README ΒΆ

HTTP Client

build status report card godocs

HTTP Client is a simple HTTP/2 client for Go.

package main

import (
	"context"
	"net/http"
	"net/url"

	"github.com/kataras/httpclient"
)

// The BaseURL of our API client.
const BaseURL = "https://api.weatherapi.com/v1"

type (
	Options struct {
		APIKey string `json:"api_key" yaml:"APIKey" toml:"APIKey"`
	}

	Client struct {
		*httpclient.Client
	}
)

func NewClient(opts Options) *Client {
	apiKeyParameterSetter := httpclient.RequestParam("key", opts.APIKey)

	c := httpclient.New(
		httpclient.BaseURL(BaseURL),
		httpclient.PersistentRequestOptions(apiKeyParameterSetter),
	)

	return &Client{c}
}

func (c *Client) GetCurrentByCity(ctx context.Context, city string) (resp Response, err error) {
	urlpath := "/current.json"
	// ?q=Athens&aqi=no
	params := httpclient.RequestQuery(url.Values{
		"q":   []string{city},
		"aqi": []string{"no"},
	})

	err = c.Client.ReadJSON(ctx, &resp, http.MethodGet, urlpath, nil, params)
	return
}

Some of the features HTTP Client offers:

  • Rate Limit
  • Middleware
  • JSON (read & write)
  • Forms
  • File Upload
  • Plain Text
  • Debug and more...

πŸ“– Learning HTTP Client

Installation

The only requirement is the Go Programming Language.

Create a new project
$ mkdir myapp
$ cd myapp
$ go mod init myapp
$ go get github.com/kataras/httpclient
Install on existing project
$ cd myapp
$ go get github.com/kataras/httpclient

Run

$ go mod tidy
$ go run .

Navigate through _examples folder for more.

πŸ“ License

This project is licensed under the MIT License.

Documentation ΒΆ

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

View Source
var IsErrEmptyJSON = func(err error) bool {
	if err == nil {
		return false
	}

	if errors.Is(err, io.EOF) {
		return true
	}

	if v, ok := err.(*json.SyntaxError); ok {

		return v.Offset == 0 && v.Error() == "unexpected end of JSON input"
	}

	errMsg := err.Error()

	return strings.Contains(errMsg, "readObjectStart: expect {") || strings.Contains(errMsg, "readArrayStart: expect [")
}

IsErrEmptyJSON reports whether the given "err" is caused by a Client.ReadJSON call when the request body was empty or didn't start with { or [.

View Source
var NoOption = func(c *Client) { c.opts = make([]Option, 0) }

NoOption is a helper function that clears the previous options in the chain. See `Client.Clone` method.

Functions ΒΆ

func BindResponse ΒΆ

func BindResponse(resp *http.Response, dest interface{}) (err error)

BindResponse consumes the response's body and binds the result to the "dest" pointer, closing the response's body is up to the caller.

The "dest" will be binded based on the response's content type header. Note that this is strict in order to catch bad actioners fast, e.g. it wont try to read plain text if not specified on the response headers and the dest is a *string.

func DecodeError ΒΆ

func DecodeError(err error, destPtr interface{}) error

DecodeError binds a json error to the "destPtr".

func DrainResponseBody ΒΆ added in v0.0.3

func DrainResponseBody(resp *http.Response) error

DrainResponseBody drains response body and close it, allowing the transport to reuse TCP connections. It's automatically called on Client.ReadXXX methods on the end.

func GetErrorCode ΒΆ

func GetErrorCode(err error) int

GetErrorCode reads an error, which should be a type of APIError, and returns its status code. If the given "err" is nil or is not an APIError it returns 200, acting as we have no error.

func RegisterRequestHandler ΒΆ

func RegisterRequestHandler(reqHandlers ...RequestHandler)

RegisterRequestHandler registers one or more request handlers to be ran before and after of each request on all newly created HTTP Clients. Useful for HTTP Client 3rd-party libraries e.g. on init register a custom request-response lifecycle logging.

Types ΒΆ

type APIError ΒΆ

type APIError struct {
	Response *http.Response
	Body     json.RawMessage // may be any []byte, response body is closed at this point.
}

APIError errors that may return from the Client.

func ExtractError ΒΆ

func ExtractError(resp *http.Response) APIError

ExtractError returns the response wrapped inside an APIError.

func GetError ΒΆ

func GetError(err error) (APIError, bool)

GetError reports whether the given "err" is an APIError.

func (APIError) Error ΒΆ

func (e APIError) Error() string

Error implements the standard error type.

type Client ΒΆ

type Client struct {
	HTTPClient *http.Client

	// BaseURL prepends to all requests.
	BaseURL string

	// A list of persistent request options.
	PersistentRequestOptions []RequestOption
	// contains filtered or unexported fields
}

A Client is an HTTP client. Initialize with the New package-level function.

func New ΒΆ

func New(opts ...Option) *Client

New returns a new HTTP Client. Available options: - BaseURL - Timeout - PersistentRequestOptions - RateLimit

Look the Client.Do/JSON/... methods to send requests and ReadXXX methods to read responses.

The default content type to send and receive data is JSON.

func (*Client) Clone ΒΆ added in v0.0.5

func (c *Client) Clone(opts ...Option) *Client

Clone returns a new Client with the same options as the original. If you want to override the options from the base "c" Client, use the `NoOption` variable as the 1st argument.

func (*Client) Do ΒΆ

func (c *Client) Do(ctx context.Context, method, urlpath string, payload interface{}, opts ...RequestOption) (*http.Response, error)

Do sends an HTTP request and returns an HTTP response.

The payload can be: - io.Reader - raw []byte - JSON raw message - string - struct (JSON).

If method is empty then it defaults to "GET". The final variadic, optional input argument sets the custom request options to use before the request.

Any HTTP returned error will be of type APIError or a timeout error if the given context was canceled.

func (*Client) Form ΒΆ

func (c *Client) Form(ctx context.Context, method, urlpath string, formValues url.Values, opts ...RequestOption) (*http.Response, error)

JSON writes form data to the server.

func (*Client) GetPlainUnquote ΒΆ

func (c *Client) GetPlainUnquote(ctx context.Context, method, urlpath string, payload interface{}, opts ...RequestOption) (string, error)

GetPlainUnquote reads the response body as raw text and tries to unquote it, useful when the remote server sends a single key as a value but due to backend mistake it sends it as JSON (quoted) instead of plain text.

func (*Client) JSON ΒΆ

func (c *Client) JSON(ctx context.Context, method, urlpath string, payload interface{}, opts ...RequestOption) (*http.Response, error)

JSON writes data as JSON to the server.

func (*Client) NewUploader ΒΆ

func (c *Client) NewUploader() *Uploader

NewUploader returns a structure which is responsible for sending file and form data to the server.

func (*Client) ReadJSON ΒΆ

func (c *Client) ReadJSON(ctx context.Context, dest interface{}, method, urlpath string, payload interface{}, opts ...RequestOption) error

ReadJSON binds "dest" to the response's body. After this call, the response body reader is closed.

If the response status code is >= 400 then it returns an APIError. If the response body is expected empty sometimes, you can omit the error through IsErrEmptyJSON.

func (*Client) ReadPlain ΒΆ

func (c *Client) ReadPlain(ctx context.Context, dest interface{}, method, urlpath string, payload interface{}, opts ...RequestOption) error

ReadPlain like ReadJSON but it accepts a pointer to a string or byte slice or integer and it reads the body as plain text.

func (*Client) RegisterRequestHandler ΒΆ

func (c *Client) RegisterRequestHandler(reqHandlers ...RequestHandler)

RegisterRequestHandler registers one or more request handlers to be ran before and after of each new request.

Request handler's BeginRequest method run after each request constructed and right before sent to the server.

Request handler's EndRequest method run after response each received and right before methods return back to the caller.

Any request handlers MUST be set right after the Client's initialization.

func (*Client) WriteTo ΒΆ

func (c *Client) WriteTo(ctx context.Context, dest io.Writer, method, urlpath string, payload interface{}, opts ...RequestOption) (int64, error)

WriteTo reads the response and then copies its data to the "dest" writer. If the "dest" is a type of HTTP response writer then it writes the content-type and content-length of the original request.

Returns the amount of bytes written to "dest".

type DebugLogger ΒΆ

type DebugLogger interface {
	Debugf(string, ...interface{})
}

type Option ΒΆ

type Option = func(*Client)

func BaseURL ΒΆ

func BaseURL(uri string) Option

BaseURL registers the base URL of this client. All of its methods will prepend this url.

func Debug ΒΆ

func Debug(logger DebugLogger) Option

Debug enables the client's debug logger. It fires right before request is created and right after a response from the server is received.

Example Output for request:

[DBUG] 2022/03/01 21:54 HTTP Client: POST / HTTP/1.1
Host: 127.0.0.1:50948
User-Agent: Go-http-client/1.1
Content-Length: 22
Accept: application/json
Content-Type: application/json
Accept-Encoding: gzip

{"firstname":"Makis"}

Example Output for response:

[DBUG] 2022/03/01 21:54 HTTP Client: HTTP/1.1 200 OK
Content-Length: 27
Content-Type: application/json; charset=utf-8
Date: Tue, 01 Mar 2022 19:54:03 GMT

{
    "firstname": "Makis"
}

func Handler ΒΆ

func Handler(h http.Handler) Option

Handler specifies an http.Handler instance which can be tested using this Client.

It registers a custom HTTP client transport which allows "fake calls" to the "h" server. Use it for testing.

func PersistentRequestOptions ΒΆ

func PersistentRequestOptions(reqOpts ...RequestOption) Option

PersistentRequestOptions adds one or more persistent request options that all requests made by this Client will respect.

func RateLimit ΒΆ

func RateLimit(requestsPerSecond int) Option

RateLimit configures the rate limit for requests.

Defaults to zero which disables rate limiting.

func Timeout ΒΆ

func Timeout(d time.Duration) Option

Timeout specifies a time limit for requests made by this Client. The timeout includes connection time, any redirects, and reading the response body. A Timeout of zero means no timeout.

Defaults to 15 seconds.

type RequestHandler ΒΆ

type RequestHandler interface {
	BeginRequest(context.Context, *http.Request) error
	EndRequest(context.Context, *http.Response, error) error
}

RequestHandler can be set to each Client instance and it should be responsible to handle the begin and end states of each request. Its BeginRequest fires right before the client talks to the server and its EndRequest fires right after the client receives a response from the server. If one of them return a non-nil error then the execution of client will stop and return that error.

type RequestOption ΒΆ

type RequestOption = func(*http.Request) error

RequestOption declares the type of option one can pass to the Do methods(JSON, Form, ReadJSON...). Request options run before request constructed.

func ClientTrace ΒΆ added in v0.0.4

func ClientTrace(clientTrace *httptrace.ClientTrace) RequestOption

ClientTrace adds a client trace to the request.

func RequestAuthorization ΒΆ

func RequestAuthorization(value string) RequestOption

RequestAuthorization sets an Authorization request header. Note that we could do the same with a Transport RoundDrip too.

func RequestAuthorizationBearer ΒΆ

func RequestAuthorizationBearer(accessToken string) RequestOption

RequestAuthorizationBearer sets an Authorization: Bearer $token request header.

func RequestHeader ΒΆ

func RequestHeader(overridePrev bool, key string, values ...string) RequestOption

RequestHeader adds or sets (if overridePrev is true) a header to the request.

func RequestParam ΒΆ

func RequestParam(key string, values ...string) RequestOption

RequestParam sets a single URL query parameter to the request.

func RequestQuery ΒΆ

func RequestQuery(query url.Values) RequestOption

RequestQuery adds a set of URL query parameters to the request.

type Uploader ΒΆ

type Uploader struct {
	Writer *multipart.Writer
	// contains filtered or unexported fields
}

Uploader holds the necessary information for upload requests.

Look the Client.NewUploader method.

func (*Uploader) AddField ΒΆ

func (u *Uploader) AddField(key, value string) error

AddFileSource adds a form field to the uploader with the given key.

func (*Uploader) AddFile ΒΆ

func (u *Uploader) AddFile(key, filename string) error

AddFile adds a local form file to the uploader with the given key.

func (*Uploader) AddFileSource ΒΆ

func (u *Uploader) AddFileSource(key, filename string, source io.Reader) error

AddFileSource adds a form file to the uploader with the given key.

func (*Uploader) Upload ΒΆ

func (u *Uploader) Upload(ctx context.Context, method, urlpath string, opts ...RequestOption) (*http.Response, error)

Uploads sends local data to the server.

Jump to

Keyboard shortcuts

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