rek

package module
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: May 13, 2020 License: MIT Imports: 15 Imported by: 17

README

rek

go.dev reference

An easy HTTP client for Go inspired by Requests, plus all the Go-specific goodies you'd hope for in a client. Here's an example:

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

comment := Comment{Body: "This movie sucked"}

headers := map[string]string{"My-Custom-Header", "foo,bar,baz"}

res, err := rek.Post("https://httpbin.org/post",
    rek.Json(comment),
    rek.Headers(headers),
    rek.BasicAuth("user", "pass"),
    rek.Timeout(5 * time.Second),
)

fmt.Println(res.StatusCode())
fmt.Println(res.Text())

Responses

The Response struct has the following methods:

Method Description Return type
StatusCode() HTTP status code, e.g. 200, 400 int
Body() The HTTP response body as a reader io.ReadCloser
Headers() The response headers map[string]string
Encoding() The content encoding of the response body, e.g. gzip []string
ContentType() The value of the Content-Type header string
Raw() The unmodified *http.Response *http.Response
Cookies() The cookies attached to the response []*http.Cookie
ContentLength() The length of the response int64
Status() The status of the response, e.g. 200 OK string
HTTP response body

Keep in mind that the HTTP response body can only be read once. This is one area in which rek does not directly correspond to the Requests API. And so this, for example, won't work the way you might want:

res, _ := rek.Get("https://httpbin.org/get")

bs1, _ := ioutil.ReadAll(res.Body()) // Non-empty byte slice

bs2, _ := ioutil.ReadAll(res.Body()) // Empty byte slice

If you'd like to use the response body more than once, store it in a variable rather than re-accessing the body.

Helper methods

There are two simple helper methods for working with the response body:

Function Return types
BodyAsString(io.ReadCloser) (string, error)
BodyAsBytes(io.ReadCloser) ([]byte, error)

Bear in mind the caveat mentioned above, that the request body can only be read once, still holds. Here are some examples:

res, _ := rek.Get("https://httpbin.org/get")

s, err := rek.BodyAsString(res.Body()) // body is read here
// handle error

bs, err := rek.BodyAsBytes(res.Body()) // bs is nil, as the body has already been read

Options

Headers
headers := map[string]string{
    "My-Custom-Header": "foo,bar,baz",
}

res, err := rek.Post("https://httpbin.org/post", rek.Headers(headers))
JSON

Pass in any struct:

type Comment struct {
    ID        int64     `json:"id"`
    Body      string    `json:"body"`
    Timestamp time.Time `json:"timestamp"`
}

comment := Comment{ID:47, Body:"Cool movie!", Timestamp: time.Now()}

res, err := rek.Post("https://httpbin.org/post", rek.Json(comment))

Request headers are automatically updated to include Content-Type as application/json;charset=utf-8.

Request timeout
res, err := rek.Get("https://httpbin.org/get", rek.Timeout(5 * time.Second))
Form data
form := map[string]string{
    "foo": "bar",
    "baq": "baz",
}

res, err := rek.Put("https://httpbin.org/put", rek.FormData(form))
File upload
fieldName := "file"
filepath := "docs/README.md"
params := nil

res, err := rek.Post("https:/httpbin.org/post", rek.File(fieldName, filepath, params))

Request headers are automatically updated to include Content-Type as multipart/form-data; boundary=....

Basic auth
username, password := "user", "pass"

res, _ := rek.Get(fmt.Sprintf("https://httpbin.org/basic-auth/%s/%s", username, password),
    rek.BasicAuth(username, password))

fmt.Println(res.StatusCode()) // 200

res, _ := rek.Get(fmt.Sprintf("https://httpbin.org/basic-auth/%s/other", username, password),
    rek.BasicAuth(username, password))

fmt.Println(res.StatusCode()) // 401
Data

Takes any input and serializes it to a []byte:

data := map[string]interface{
    "age": 38,
    "name": "Luc",
}

res, err := rek.Post("https://httpbin.org/post", rek.Data(data))

Request headers are automatically updated to include Content-Type as application/octet-stream.

User agent
res, err := rek.Post("https://httpbin.org/post", rek.UserAgent("ThisGuy"))
Bearer (useful for JSON Web Tokens)
token := "... token ..."

res, err := rek.Post("https://httpbin.org/post", rek.Bearer(token))
Request modifier

Supply a function that modifies the *http.Request (after all other supplied options have been applied to the request):

modifier := func(r *http.Request) {
   // Do whatever you want with the request
}

res, err := rek.Get("https://httpbin.org/get", rek.RequestModifier(modifier))
Accept

Apply an Accept header to the request:

res, err := rek.Get("https://httpbin.org/get", rek.Accept("application/tar+gzip"))
API key

Add an API key to the request as an Authorization header (where the value is Basic ${KEY}):

res, err := rek.Get("https://some-secure-api.io", rek.ApiKey("a1b2c3..."))
Context

Supply a Context to the request:

ctx, cancel := context.WithCancel(context.Background())

res, err := rek.Get("https://long-winded-api.io", rek.Context(ctx))

// Ugh, I don't want this request to happen anymore

cancel()
OAuth2

You can add an OAuth2 configuration and token to your request:

conf := &oauth2.Config{
	ClientID:     "YOUR_CLIENT_ID",
	ClientSecret: "YOUR_CLIENT_SECRET",
	Scopes:       []string{"SCOPE1", "SCOPE2"},
	Endpoint: oauth2.Endpoint{
		AuthURL:  "https://provider.com/o/oauth2/auth",
		TokenURL: "https://provider.com/o/oauth2/token",
	},
}

tok, err := conf.Exchange(ctx, code)
// handle error

res, err := rek.Get("https://oauth2-protected-site.com", rek.OAuth2(conf, tok))

Custom client

You can pass in your own *http.Client as the basis for the request:

client := &http.Client{
    // Custom attributes
}

res, err := rek.Get("https://httpbin.org/get", rek.Client(client))

Validation

It's important to bear in mind that rek provides no validation for the options that you provide on a specific request and doesn't provide any constraints on which options can be used with which request method. Some options may not make sense for some methods, e.g. request JSON on a HEAD request, but I leave it up to the end user to supply their own constraints. One exception is that the request body can only be set once. If you attempt to set it more than once you'll get a ErrRequestBodySetMultipleTimes error. This, for example, will throw that error:

comment := Comment{Body: "This movie sucked"}

_, err := rek.Post("https://httpbin.org/post",
    rek.Json(comment),
    rek.FormData(map[string]string{"foo": "bar"}))

fmt.Println(err == rek.ErrRequestBodySetMultipleTimes) // true

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrRequestBodySetMultipleTimes = errors.New("you have set the request body more than once")

The error thrown when you attempt to set the HTTP request body more than once

Functions

func BodyAsBytes added in v0.1.2

func BodyAsBytes(r io.ReadCloser) ([]byte, error)

The response body as a byte slice. Bear in mind that the response body can only be read once.

func BodyAsString added in v0.1.2

func BodyAsString(r io.ReadCloser) (string, error)

The response body as a string. Bear in mind that the response body can only be read once.

Types

type Option added in v0.1.3

type Option func(*options)

func Accept

func Accept(accept string) Option

Applies an Accept header to the request.

func ApiKey added in v0.1.1

func ApiKey(key string) Option

Adds an API key to the request.

func BasicAuth

func BasicAuth(username, password string) Option

Add a basic auth username and password to the request.

func Bearer

func Bearer(bearer string) Option

Add a bearer header of the form "Authorization: Bearer ..."

func Callback

func Callback(cb func(*Response)) Option

Add a callback function for handling the Response.

func Client added in v0.1.2

func Client(client *http.Client) Option

Provide your own http.Client struct to make the request.

func Context added in v0.1.1

func Context(ctx context.Context) Option

Pass a context into the HTTP request (allows for request cancellation, for example).

func CookieJar

func CookieJar(jar http.CookieJar) Option

Add a cookie jar to the request.

func Cookies

func Cookies(cookies []*http.Cookie) Option

Add cookies to the request.

func Data

func Data(data interface{}) Option

Add any interface{} that can be serialized to a []byte and apply a "Content-Type: application/octet-stream" header.

func DisallowRedirects

func DisallowRedirects() Option

Turn redirects off.

func File

func File(fieldName, filepath string, params map[string]string) Option

Create a multipart file upload request.

func FormData

func FormData(form map[string]string) Option

Add key/value form data to the request body and apply a "Content-Type: application/x-www-form-urlencoded" header.

func Headers

func Headers(headers map[string]string) Option

Add headers to the request.

func Json

func Json(v interface{}) Option

Add any interface{} that can be marshaled as JSON to the request body and apply a "Content-Type: application/json;charset=utf-8" header.

func OAuth2 added in v0.1.2

func OAuth2(cfg *oauth2.Config, tok *oauth2.Token) Option

Apply an OAuth2 configuration and token to the request.

func RequestModifier added in v0.1.1

func RequestModifier(modifier func(*http.Request)) Option

Applies a user-provided request modification function. Applied after all other request modifications have been made by the selected options.

func Timeout

func Timeout(timeout time.Duration) Option

Add a timeout to the request.

func UserAgent

func UserAgent(agent string) Option

Add a User-Agent header to the request.

type Response

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

A struct containing the relevant response information returned by a rek request.

func Delete

func Delete(url string, opts ...Option) (*Response, error)

DELETE request

func Do added in v0.1.2

func Do(method, url string, opts ...Option) (*Response, error)

Make a request with an arbitrary HTTP method, i.e. not GET, POST, PUT, DELETE, etc.

func Get

func Get(url string, opts ...Option) (*Response, error)

GET request

func Head(url string, opts ...Option) (*Response, error)

HEAD request

func Patch

func Patch(url string, opts ...Option) (*Response, error)

PATCH request

func Post

func Post(url string, opts ...Option) (*Response, error)

POST request

func Put

func Put(url string, opts ...Option) (*Response, error)

PUT request

func (*Response) Body added in v0.1.2

func (r *Response) Body() io.ReadCloser

The response body as a io.ReadCloser. Bear in mind that the response body can only be read once.

func (*Response) ContentLength

func (r *Response) ContentLength() int64

The content length of the response body.

func (*Response) ContentType

func (r *Response) ContentType() string

The Content-Type header for the request (if any).

func (*Response) Cookies

func (r *Response) Cookies() []*http.Cookie

The cookies associated with the response.

func (*Response) Encoding

func (r *Response) Encoding() []string

The response's encoding.

func (*Response) Headers

func (r *Response) Headers() map[string]string

The headers associated with the response.

func (*Response) Raw

func (r *Response) Raw() *http.Response

The raw *http.Response returned by the operation.

func (*Response) Status

func (r *Response) Status() string

The response's status, e.g. "200 OK."

func (*Response) StatusCode

func (r *Response) StatusCode() int

The status code of the response (200, 404, etc.).

Jump to

Keyboard shortcuts

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