please

package module
v1.0.8 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2021 License: NCSA Imports: 15 Imported by: 2

README

Please: Ask nicely.

Please is a slightly more idiomatic Golang requests helper that serves as a wrapper around the net/http http.Client. Unlike many other similar projects, it doesn't blindly copy the python-requests API, nor does it provide some of the amenities one might expect from mostly-automatic-HTTP-request-handling. It does support method chaining, and the API attempts to read more politely than most, thereby presenting your maintenance programmer (or future you!) with a happier story when things suddenly stop working as intended.

Why Please?

There are many client libraries for Go that provide a wide array of APIs and philosophical differences ranging from Python-esque to pathologically idiomatic Go. This library hopes to sit somewhere in between these two extremes by providing an easily chainable API that exposes wrapped net/http client types.

If you wish to see an example of Please at work, the currently-a-work-in-progress framework Capstan uses it internally for client-side HTTP unit tests.

Usage

To use Please simply:

$ go get git.destrealm.org/go/please

The Please API is quite simple. Here is a demonstration of a GET request to httpbin.org:

Sample Code

type httpbinJSON struct {
	Args    map[string]string `json:"args,omitempty"`
	Headers map[string]string `json:"headers,omitempty"`
	Origin  string            `json:"origin,omitempty"`
	URL     string            `json:"url,omitempty"`
	JSON    map[string]string `json:"json,omitempty"`
}

func Get() error {
    var data httpbinJSON

    // Create the request.
    request := please.Get("http://httpbin.org/get")

    // Send the request and retrieve the response.
    //
    // .Request() is required after .Add() to retrieve the underlying request
    // instance, otherwise multiple .Add()s may be chained together.
    response, err := request.Query().Add("sample", "value").Request().Send()
    if err != nil {
        return err
    }

    // Load the response into a pointer to `data`.
    if err := response.JSON(&data); err != nil {
        return err
    }

    fmt.Printf("received: %v\n", data)
}

As you can see, while the API isn't as simple as many other competing libraries, the calls between creating the client request and calling request.Send() provide a fair bit of flexibility without requiring varargs or passing around interfaces. Because Please is mostly a convenience wrapper around http.Client, it's trivial to leverage existing functionality without relying on too magic. Leastwise, the magic that exists outside mildly excessive method chaining.

More Work to be Done!

Nevertheless, Please requires much more work to be done. In particular, API documentation needs to be written, and some internal refactoring certainly couldn't hurt.

Once you've submitted the request via Send, Please does provide a couple of conveniences:

  • Headers() returns the http.Header associated with the response.
  • JSON() reads the response into a JSON-tagged struct, provided the response contains valid JSON.
  • ReadAll() reads the entire response body.
  • Body() provides an io.Reader to read the response body if you have a need that isn't completely fulfilled with ReadAll().

Prior to commit, there are:

  • Form() returns a pointer to the form values to send with the request. Only works with POST-compatible queries (POST and PUT mostly). Otherwise any values set via this method will be ignored.
  • Headers() returns a pointer to the request headers for manipulation prior to the request.
  • Query() returns a pointer to a url.Values instance that can be modified to add or remove query string values.
  • WriteJSON() accepts an interface that must be a JSON-tagged struct to be converted into a JSON request body.

We also have available the option to add "code handlers," which are functions that are called based upon the response code returned by the server. These can be assigned via On() or applied broadly using Each(). As with many of the features mentioned above, code handlers need further documentation!

For more examples, please refer to the request-cycle unit tests.

License

Please is offered under the terms of the NCSA license. This is a liberal license that allows for commercial use provided attribution is given. Additionally, and somewhat distinctly from similar licenses (BSD and MIT in particular), this license also extends to documentation included with the distribution.

Copyright (c) 2021 Benjamin A. Shelton.

Documentation

Index

Constants

View Source
const MaxRetentionSize = 1024 * 50

MaxRetentionSize for responses. Mostly used by response.JSON. If the response body is less than this, it will be replaced with a bytes.Buffer containing the responseif client.Response.ReadAll() and client.Response.JSON() are used. Obviously, directly accessing the response body will nullify any benefit from this.

Variables

View Source
var DefaultUserAgent = "please/1.0 (compatible; ask nicely; http://git.destrealm.org/go/please)"

DefaultUserAgent with which to identify. Changing this value will modify the user-agent sent alongside all requests.

View Source
var ErrClientInitialization = errors.NewError("error initializing client")

ErrClientInitialization is raised by TLS-enabled clients whenever the assigned server certificate cannot be loaded or parsed.

View Source
var ErrClientRequest = errors.NewError("error in client with request setup or completion")

ErrClientRequest is raised whenever an error occurs during a client request.

View Source
var ErrEncoding = errors.NewError("error encoding data")

ErrEncoding is returned whenever an error occurs while encoding data, be it JSON or otherwise.

View Source
var ErrParsingQuery = errors.NewError("error parsing query string")
View Source
var ErrParsingURL = errors.NewError("error parsing URL")

ErrParsingURL is returned by the HTTP client if a given URL cannot be parsed.

View Source
var ErrRenderingURL = errors.NewError("unable to render URL")
View Source
var ErrVariableOffset = errors.NewError("variable offset exceeds template bounds")

Functions

This section is empty.

Types

type CodeHandler

type CodeHandler func(Requester, Response, error) error

CodeHandler defines the function type to use for per-response or per-response code handlers.

type HeaderProxy

type HeaderProxy interface {
	Proxy
	Err() error
	Write(io.Writer) HeaderProxy
	WriteSubset(io.Writer, map[string]bool) HeaderProxy
}

type Proxy

type Proxy interface {
	Add(string, string) Proxy
	Del(string) Proxy
	Get(string) string
	Set(string, string) Proxy
	Request() Requester
	Values(string) []string
}

type RequestProxy

type RequestProxy interface {
	Requester() Requester
	Request() *http.Request
	Send() (Response, error)
}

type Requester

type Requester interface {
	Body(io.Reader) Requester
	Clone() Requester
	ChangeUserAgent(ua string) Requester
	Method(method string) Requester
	To(method string) Requester
	Set(tplkey string, tplval string) Requester
	SetClient(client *http.Client) Requester
	SetURL(url string) Requester
	WriteJSON(data interface{}) Requester
	Get(paths ...string) Requester
	Delete(paths ...string) Requester
	Head(paths ...string) Requester
	Patch(paths ...string) Requester
	Post(paths ...string) Requester
	Put(paths ...string) Requester
	WithCertificatePath(path string) Requester
	WithTLS() Requester
	WithUnverifiedTLS() Requester
	WithContext(context.Context) Requester
	WithPath(paths ...string) Requester
	WithQuery(qs string) Requester
	Each(CodeHandler) Requester
	Client() *http.Client
	Err() error
	Headers() HeaderProxy
	Parent() Requester
	Form() Proxy
	Query() Proxy
	Prepare() (RequestProxy, error)
	Send() (Response, error)
}

func Ask

func Ask(u string) Requester

Ask nicely.

This is a polite alias for Request.

func Delete

func Delete(u string) Requester

Delete creates a request instance for DELETE requests.

func Get

func Get(u string) Requester

Get creates a request instance for GET requests.

This method is included for sake of completeness. Please's default state is to issue GET requests. This should be considered a noop.

func Head(u string) Requester

Head creates a request instance for HEAD requests.

func Patch

func Patch(u string) Requester

Patch creates a request instance for PATCH requests.

func Post

func Post(u string) Requester

Post creates a request instance for POST requests.

func Put

func Put(u string) Requester

Put creates a request instance for PUT requests.

func Request

func Request(u string) Requester

Request creates a new request using baseURL as the request URI path.

type Response

type Response interface {
	Body() io.Reader
	Code() int
	Response() *http.Response
	Headers() http.Header
	JSON(v interface{}) error
	ReadAll() ([]byte, error)
}

Response is an interface returned by Requester.Send() and encapsulates the server response.

Jump to

Keyboard shortcuts

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