Categorygithub.com/contextgg/requester
modulepackage
1.2.1
Repository: https://github.com/contextgg/requester.git
Documentation: pkg.go.dev

# README

Requester

GoDoc Go Report Card Build

A.K.A "Yet Another Golang Requests Package"

Requester makes it a bit simpler to use Go's http package as a client. As an example, take a simple request, with the http package:

bodyBytes, err := json.Marshal(reqBodyStruct)
if err != nil { return err }

bodyBytes, err := json.Marshal(requestBody)
if err != nil {
   panic(err)
}

req, err := http.NewRequest("POST", "http://api.com/resources/", bytes.NewReader(bodyBytes))
if err != nil {
   panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")

resp, err := http.DefaultClient.Do(req)
if err != nil {
   panic(err)
}

if resp.StatusCode != 201 {
   panic(errors.New("expected code 201"))
}

respBody, _ := ioutil.ReadAll(resp.Body)
var r Resource
if err := json.Unmarshal(respBody, &r); err != nil {
   panic(err)
}

fmt.Printf("%d %s %v", resp.StatusCode, string(respBody), r)

requester uses functional options to configure the request, and folds request building, execution, and response handling into a single call:

var r Resource

resp, body, err := requester.ReceiveContext(ctx, &r,
   requester.JSON(false),
   requester.Body(requestBody),
   requester.Post("http://api.com/resources/"),
   requester.ExpectCode(201),
)
if err != nil {
   panic(err)
}

fmt.Printf("%d %s %v", resp.StatusCode, string(body), r)

Installation

go get github.com/gemalto/requester

Note: this repo was moved to github.com/ThalesGroup, but the name of the module is still github.com/gemalto: that is the name you must use to install with go modules.

Features

  • Functional option pattern supports an ergonomic API
  • Options for configuring http.Client options
  • Tools for writing unit tests, like Inspector{}, MockDoer(), MockHandler(), and the httptestutil package
  • Embeddable
  • Client-side middleware (see Middleware and Doer)
  • context.Context support

Core API

The core functions are available on the package, or on instances of Requester{}.

// just build a request
Request(...Option) (*http.Request, error)
RequestContext(context.Context, ...Option) (*http.Request, error)

// build a request and execute it
Send(...Option) (*http.Response, error)
SendContext(context.Context, ...Option) (*http.Response, error)

// build and send a request, and handle the response
Receive(interface{}, ...Option) (*http.Response, []byte, error)
ReceiveContext(context.Context, interface{}, ...Option) (*http.Response, []byte, error)

Receive/ReceiveContext reads and closes the response body, returns it as a byte slice, and also attempts to unmarshal it into a target value, if one is provided. 

Each of these accept variadic functional options, which alter the request, the http.Client, or the control how to process the response. Option is defined as:

type Option interface {
   Apply(*Requester) error
}

FAQ

  • Why, when there are like, 50 other packages that do the exact same thing?

Yeah, good question. This library started as a few tweaks to https://github.com/dghubble/sling. Then it became more of a fork, then a complete rewrite, inspired by a bunch of other similar libraries.

A few things bugged me about other libraries:

  1. Some didn't offer enough control over the base http primitives, like the underlying http.Client, and all the esoteric attributes of http.Request.

  2. I wanted more control over marshaling and unmarshaling bodies, without sacrificing access to the raw body.

  3. Some libraries which offer lots more control or options also seemed to be much more complicated, or less idiomatic.

  4. Most libraries don't handle context.Contexts at all.

  5. The main thing: most other libraries use a "fluent" API, where you call methods on a builder instance to configure the request, and these methods each return the builder, making it simple to call the next method, something like this:

     req.Get("http://api.com").Header("Content-Type", "application/json").Body(reqBody)
     
    

    I used to like fluent APIs in other languages, but they don't feel right in Go. You typically end up deferring errors until later, so the error doesn't surface near the code that caused the error. Its difficult to mix fluent APIs with interfaces, because the concrete types tend to have lots of methods, and they all have to return the same concrete type. For the same reason, it's awkward to embed types with fluent APIs. Fluent APIs also make it hard to extend the library with additional, external options.

Requester swaps a fluent API for the functional option pattern. This hopefully keeps a fluent-like coding style, while being more idiomatic Go. Since Options are just a simple interface, it's easy to bring your own options, or contribute new options back to this library.

Also, making the options into objects improved ergonomics in a few places, like mirroring the main functions (Request(), Send(), Receive()) on the struct and the package. Options can be passed around as arguments or accumulated in slices.

Contributing

To build, be sure to have a recent go SDK, and make. Run make tools to install other dependencies. Run make to build.

Merge requests are welcome! Before submitting, please run make and make sure all tests pass and there are no linter findings.

# Packages

Package httpclient is a set of utilities for creating and configuring instances of http.Client.
Package httptestutil contains utilities for use in HTTP tests, particular when using httptest.Server.

# Functions

Accept sets the Accept header.
AddHeader adds a header value, using Header.Add().
AllRetryers returns a ShouldRetryer which returns true only if all the supplied retryers return true.
AppendPath appends path elements to the end of the URL.Path.
BasicAuth sets the Authorization header to "Basic <encoded username and password>".
BearerAuth sets the Authorization header to "Bearer <token>".
Body sets the body of the request.
ChannelDoer returns a DoerFunc and a channel.
ChannelHandler returns an http.Handler and an input channel.
Client replaces Requester.Doer with an *http.Client.
ContentType sets the Content-Type header.
DefaultShouldRetry is the default ShouldRetryer.
Delete sets the HTTP method to "DELETE".
DeleteHeader deletes a header key, using Header.Del().
Dump dumps requests and responses to a writer.
DumpToLog dumps the request and response to a logging function.
DumpToStderr dumps requests and responses to os.Stderr.
DumpToStout dumps requests and responses to os.Stdout.
ExpectCode generates an error if the response's status code does not match the expected code.
ExpectSuccessCode is middleware which generates an error if the response's status code is not between 200 and 299.
Form sets Requester.Marshaler to the FormMarshaler, which marshals the body into form-urlencoded.
Get sets the HTTP method to "GET".
Head sets the HTTP method to "HEAD".
Header sets a header value, using Header.Set().
Host sets Requester.Host.
Inspect installs and returns an Inspector.
JSON sets Requester.Marshaler to the JSONMarshaler.
Method sets the HTTP method (e.g.
MockDoer creates a Doer which returns a mocked response, for writing tests.
MockHandler returns an http.Handler which returns responses built from the args.
MockResponse creates an *http.Response from the Options.
MustNew creates a new Requester, applying all options.
New returns a new Requester, applying all options.
NewContentTypeUnmarshaler returns a new ContentTypeUnmarshaler preconfigured to handle application/json and application/xml.
OnlyIdempotentShouldRetry returns true if the request is using one of the HTTP methods which are intended to be idempotent: GET, HEAD, OPTIONS, and TRACE.
Patch sets the HTTP method to "PATCH".
Post
Post sets the HTTP method to "POST".
Put sets the HTTP method to "PUT".
QueryParam adds a query parameter.
QueryParams adds params to the Requester.QueryParams member.
Range sets the Range header.
Receive uses the DefaultRequester to create a request, execute it, and read the response.
ReceiveContext does the same as Receive(), but attaches a Context to the request.
RelativeURL resolves the arg as a relative URL references against the current URL, using the standard lib's url.URL.ResolveReference() method.
Request uses the DefaultRequester to create a request.
RequestContext does the same as Request(), but attaches a Context to the request.
Retry retries the http request under certain conditions.
Send uses the DefaultRequester to create a request and execute it.
SendContext does the same as Send(), but attaches a Context to the request.
URL sets the request URL.
Use appends middlware to Requester.Middleware.
WithDoer replaces Requester.Doer.
WithMarshaler sets Requester.WithMarshaler.
WithUnmarshaler sets Requester.WithUnmarshaler.
Wrap applies a set of middleware to a Doer.
XML sets Requester.Marshaler to the XMLMarshaler.

# Constants

HTTP constants.
HTTP constants.
HTTP constants.
HTTP constants.
HTTP constants.
HTTP constants.
HTTP constants.
HTTP constants.
HTTP constants.
HTTP constants.
HTTP constants.

# Variables

DefaultBackoff is a backoff configuration with the default values.
DefaultMarshaler is used by Requester if Requester.Marshaler is nil.
DefaultRequester is the singleton used by the package-level Request/Send/Receive functions.
DefaultRetryConfig is the default retry configuration used if nil is passed to Retry().
DefaultUnmarshaler is used by Requester if Requester.Unmarshaler is nil.

# Structs

ContentTypeUnmarshaler selects an unmarshaler based on the content type, which should be a valid media/mime type, in the form: type "/" [tree "."] subtype ["+" suffix] *[";" parameter] Unmarshalers are registered to handle a given media type.
ExponentialBackoff defines the configuration options for an exponential backoff strategy.
FormMarshaler implements Marshaler.
Inspector is a Requester Option which captures requests and responses.
JSONMarshaler implement Marshaler and Unmarshaler.
Requester is an HTTP request builder and HTTP client.
RetryConfig defines settings for the Retry middleware.
XMLMarshaler implements Marshaler and Unmarshaler.

# Interfaces

Backoffer calculates how long to wait between attempts.
Doer executes http requests.
Marshaler marshals values into a []byte.
Option applies some setting to a Requester object.
ShouldRetryer evaluates whether an HTTP request should be retried.
Unmarshaler unmarshals a []byte response body into a value.

# Type aliases

BackofferFunc adapts a function to the Backoffer interface.
DoerFunc adapts a function to implement Doer.
MarshalFunc adapts a function to the Marshaler interface.
Middleware can be used to wrap Doers with additional functionality.
MultiUnmarshaler is a legacy alias for ContentTypeUnmarshaler.
OptionFunc adapts a function to the Option interface.
ShouldRetryerFunc adapts a function to the ShouldRetryer interface.
UnmarshalFunc adapts a function to the Unmarshaler interface.