requests

package module
v0.21.2 Latest Latest
Warning

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

Go to latest
Published: May 24, 2021 License: MIT Imports: 12 Imported by: 228

README

Requests GoDoc Go Report Card

Requests logo

HTTP requests for Gophers.

The requests.Builder type is a convenient way to build, send, and handle HTTP requests. Builder has a fluent API with methods returning a pointer to the same struct, which allows for declaratively describing a request by method chaining.

Examples

// Simple GET into a string
var s string
err := requests.
	URL("http://example.com").
	ToString(&s).
	Fetch(context.Background())

// Equivalent code with net/http
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.com", nil)
if err != nil {
	// ...
}
res, err := http.DefaultClient.Do(req)
if err != nil {
	// ...
}
defer res.Body.Close()
b, err := io.ReadAll(res.Body)
if err != nil {
	// ...
}
s := string(b)
// 5 lines vs. 13 lines
// Post a raw body
err := requests.
	URL("https://postman-echo.com/post").
	BodyBytes([]byte(`hello, world`)).
	ContentType("text/plain").
	Fetch(context.Background())

// Equivalent code with net/http
body := bytes.NewReader(([]byte(`hello, world`))
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://postman-echo.com/post", body)
if err != nil {
	// ...
}
req.Header.Set("Content-Type", "text/plain")
res, err := http.DefaultClient.Do(req)
if err != nil {
	// ...
}
defer res.Body.Close()
_, err := io.ReadAll(res.Body)
if err != nil {
	// ...
}
// 5 lines vs. 14 lines
// GET a JSON object
var post placeholder
err := requests.
	URL("https://jsonplaceholder.typicode.com").
	Path("/posts/1").
	ToJSON(&post).
	Fetch(context.Background())

// Equivalent code with net/http
var post placeholder
u, err := url.Parse("https://jsonplaceholder.typicode.com")
if err != nil {
	// ...
}
u.Path = "/posts/1"
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), body)
if err != nil {
	// ...
}
req.Header.Set("Content-Type", "text/plain")
res, err := http.DefaultClient.Do(req)
if err != nil {
	// ...
}
defer res.Body.Close()
b, err := io.ReadAll(res.Body)
if err != nil {
	// ...
}
err := json.Unmarshal(b, &post)
if err != nil {
	// ...
}
// 6 lines vs. 23 lines
// POST a JSON object and parse the response
var res placeholder
req := placeholder{
	Title:  "foo",
	Body:   "baz",
	UserID: 1,
}
err := requests.
	URL("/posts").
	Host("jsonplaceholder.typicode.com").
	BodyJSON(&req).
	ToJSON(&res).
	Fetch(context.Background())
// net/http equivalent left as an exercise for the reader
// Set headers
var headers postman
err := requests.
	URL("https://postman-echo.com/get").
	UserAgent("bond/james-bond").
	ContentType("secret").
	Header("martini", "shaken").
	Fetch(context.Background())
var params postman
err := requests.
	URL("https://postman-echo.com/get?a=1&b=2").
	Param("b", "3").
	Param("c", "4").
	Fetch(context.Background())
	// URL is https://postman-echo.com/get?a=1&b=3&c=4

Documentation

Overview

Package requests is a convenience wrapper around net/http to make it faster and easier to build requests and custom transports.

Example
package main

import (
	"context"
	"fmt"
	"strings"

	"github.com/carlmjohnson/requests"
)

func main() {
	// Simple GET into a string
	var s string
	err := requests.
		URL("http://example.com").
		ToString(&s).
		Fetch(context.Background())
	if err != nil {
		fmt.Println("could not connect to example.com:", err)
	}
	fmt.Println(strings.Contains(s, "Example Domain"))
}
Output:
true
Example (Bufio)
package main

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"strings"

	"github.com/carlmjohnson/requests"
)

func main() {
	// read a response line by line for a sentinel
	found := false
	err := requests.
		URL("http://example.com").
		ToBufioReader(func(r *bufio.Reader) error {
			var err error
			for s := ""; err == nil; {
				if strings.Contains(s, "Example Domain") {
					found = true
					return nil
				}
				// read one line from response
				s, err = r.ReadString('\n')
			}
			if err == io.EOF {
				return nil
			}
			return err
		}).
		Fetch(context.Background())
	if err != nil {
		fmt.Println("could not connect to example.com:", err)
	}
	fmt.Println(found)
}
Output:
true
Example (BytesBuffer)
package main

import (
	"bytes"
	"context"
	"fmt"
	"strings"

	"github.com/carlmjohnson/requests"
)

func main() {
	// Simple GET into a buffer
	var buf bytes.Buffer
	err := requests.
		URL("http://example.com").
		ToBytesBuffer(&buf).
		Fetch(context.Background())
	if err != nil {
		fmt.Println("could not connect to example.com:", err)
	}
	fmt.Println(strings.Contains(buf.String(), "Example Domain"))
}
Output:
true
Example (ExpectStatus)
package main

import (
	"context"
	"fmt"

	"github.com/carlmjohnson/requests"
)

func main() {
	// Expect a specific status code
	err := requests.
		URL("https://jsonplaceholder.typicode.com/posts/9001").
		CheckStatus(404).
		CheckContentType("application/json").
		Fetch(context.Background())
	if err != nil {
		fmt.Println("should be a 404:", err)
	} else {
		fmt.Println("OK")
	}
}
Output:
OK
Example (FormValue)
package main

import (
	"context"
	"fmt"
	"net/url"

	"github.com/carlmjohnson/requests"
)

// Examples with the Postman echo server
type postman struct {
	Args    map[string]string `json:"args"`
	Data    string            `json:"data"`
	Headers map[string]string `json:"headers"`
	JSON    map[string]string `json:"json"`
}

func main() {
	// Submit form values
	var echo postman
	err := requests.
		URL("https://postman-echo.com/put").
		Put().
		BodyForm(url.Values{
			"hello": []string{"world"},
		}).
		ToJSON(&echo).
		Fetch(context.Background())
	if err != nil {
		fmt.Println("problem with postman:", err)
	}
	fmt.Println(echo.JSON)
}
Output:
map[hello:world]
Example (GetJSON)
package main

import (
	"context"
	"fmt"

	"github.com/carlmjohnson/requests"
)

type placeholder struct {
	ID     int    `json:"id,omitempty"`
	Title  string `json:"title"`
	Body   string `json:"body"`
	UserID int    `json:"userId"`
}

func main() {
	// GET a JSON object
	var post placeholder
	err := requests.
		URL("https://jsonplaceholder.typicode.com").
		Path("/posts/1").
		ToJSON(&post).
		Fetch(context.Background())
	if err != nil {
		fmt.Println("could not connect to jsonplaceholder.typicode.com:", err)
	}
	fmt.Println(post.Title)
}
Output:
sunt aut facere repellat provident occaecati excepturi optio reprehenderit
Example (Header)
package main

import (
	"context"
	"fmt"

	"github.com/carlmjohnson/requests"
)

// Examples with the Postman echo server
type postman struct {
	Args    map[string]string `json:"args"`
	Data    string            `json:"data"`
	Headers map[string]string `json:"headers"`
	JSON    map[string]string `json:"json"`
}

func main() {
	// Set headers
	var headers postman
	err := requests.
		URL("https://postman-echo.com/get").
		UserAgent("bond/james-bond").
		ContentType("secret").
		Header("martini", "shaken").
		ToJSON(&headers).
		Fetch(context.Background())
	if err != nil {
		fmt.Println("problem with postman:", err)
	}
	fmt.Println(headers.Headers["user-agent"])
	fmt.Println(headers.Headers["content-type"])
	fmt.Println(headers.Headers["martini"])
}
Output:
bond/james-bond
secret
shaken
Example (PostJSON)
package main

import (
	"context"
	"fmt"

	"github.com/carlmjohnson/requests"
)

type placeholder struct {
	ID     int    `json:"id,omitempty"`
	Title  string `json:"title"`
	Body   string `json:"body"`
	UserID int    `json:"userId"`
}

func main() {
	// POST a JSON object and parse the response
	var res placeholder
	req := placeholder{
		Title:  "foo",
		Body:   "baz",
		UserID: 1,
	}
	err := requests.
		URL("/posts").
		Host("jsonplaceholder.typicode.com").
		BodyJSON(&req).
		ToJSON(&res).
		Fetch(context.Background())
	if err != nil {
		fmt.Println("could not connect to jsonplaceholder.typicode.com:", err)
	}
	fmt.Println(res)
}
Output:
{101 foo baz 1}
Example (QueryParam)
package main

import (
	"context"
	"fmt"

	"github.com/carlmjohnson/requests"
)

// Examples with the Postman echo server
type postman struct {
	Args    map[string]string `json:"args"`
	Data    string            `json:"data"`
	Headers map[string]string `json:"headers"`
	JSON    map[string]string `json:"json"`
}

func main() {
	// Set a query parameter
	var params postman
	err := requests.
		URL("https://postman-echo.com/get?a=1&b=2").
		Param("b", "3").
		Param("c", "4").
		ToJSON(&params).
		Fetch(context.Background())
	if err != nil {
		fmt.Println("problem with postman:", err)
	}
	fmt.Println(params.Args)
}
Output:
map[a:1 b:3 c:4]
Example (RawBody)
package main

import (
	"context"
	"fmt"

	"github.com/carlmjohnson/requests"
)

// Examples with the Postman echo server
type postman struct {
	Args    map[string]string `json:"args"`
	Data    string            `json:"data"`
	Headers map[string]string `json:"headers"`
	JSON    map[string]string `json:"json"`
}

func main() {
	// Post a raw body
	var data postman
	err := requests.
		URL("https://postman-echo.com/post").
		BodyBytes([]byte(`hello, world`)).
		ContentType("text/plain").
		ToJSON(&data).
		Fetch(context.Background())
	if err != nil {
		fmt.Println("problem with postman:", err)
	}
	fmt.Println(data.Data)
}
Output:
hello, world

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func HasStatusErr

func HasStatusErr(err error, codes ...int) bool

HasStatusErr returns true if err is a StatusError caused by any of the codes given.

Example
package main

import (
	"context"
	"fmt"

	"github.com/carlmjohnson/requests"
)

func main() {
	err := requests.
		URL("http://example.com/404").
		CheckStatus(200).
		Fetch(context.Background())
	if requests.HasStatusErr(err, 404) {
		fmt.Println("got a 404")
	}
}
Output:
got a 404

func WrapRoundTripper

func WrapRoundTripper(rt http.RoundTripper, f func(r *http.Request)) http.RoundTripper

WrapRoundTripper deep clones a request and passes it to f before calling the underlying RoundTripper. If rt is nil, it calls http.DefaultTransport.

func WrapTransport

func WrapTransport(c *http.Client, f func(r *http.Request))

WrapTransport sets c.Transport to a WrapRoundTripper.

Types

type BodyGetter

type BodyGetter = func() (io.ReadCloser, error)

BodyGetter provides a Builder with a source for a request body.

func BodyBytes

func BodyBytes(b []byte) BodyGetter

BodyBytes is a BodyGetter that returns the provided raw bytes.

func BodyForm

func BodyForm(data url.Values) BodyGetter

BodyForm is a BodyGetter that builds an encoded form body.

func BodyJSON

func BodyJSON(v interface{}) BodyGetter

BodyJSON is a BodyGetter that marshals a JSON object.

func BodyReader

func BodyReader(r io.Reader) BodyGetter

BodyReader is a BodyGetter that returns an io.Reader.

type Builder

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

Builder is a convenient way to build, send, and handle HTTP requests. Builder has a fluent API with methods returning a pointer to the same struct, which allows for declaratively describing a request by method chaining.

Builder can be thought of as having the following phases:

Set the base URL for a request with requests.URL then customize it with Host, Hostf, Path, Pathf, and Param.

Set the method for a request with Method or use the Get, Post, and Put methods.

Set headers with Header or set conventional header keys with ContentType, UserAgent, and BasicAuth.

Add a validator to the Builder with AddValidator or use the built in CheckStatus and CheckContentType.

Set the http.Client to use for a request with Client.

Set the body of the request if any with GetBody or use built in BodyBytes, BodyJSON, or BodyReader.

Set a handler for a response with Handle or use ToJSON, ToString, ToBytesBuffer, or ToBufioReader.

Fetch creates an http.Request with Request and sends it via the underlying http.Client with Do.

In many cases, it will be possible to set most options for an API endpoint in a Builder at the package level and then call Clone in a function to add request specific URL parameters, headers, body, and handler. The zero value of Builder is usable but at least the Host parameter must be set before fetching.

func URL

func URL(u string) *Builder

URL creates a new Builder suitable for method chaining.

func (*Builder) AddValidator

func (rb *Builder) AddValidator(h ResponseHandler) *Builder

AddValidator adds a response validator to the Builder. Adding a validator disables DefaultValidator. To disable all validation, just add nil.

func (*Builder) BasicAuth

func (rb *Builder) BasicAuth(username, password string) *Builder

BasicAuth sets the Authorization header to a basic auth credential.

func (*Builder) BodyBytes

func (rb *Builder) BodyBytes(b []byte) *Builder

BodyBytes sets the Builder's request body to b.

func (*Builder) BodyForm

func (rb *Builder) BodyForm(data url.Values) *Builder

BodyForm sets the Builder's request body to the encoded form. It also sets the ContentType to "application/x-www-form-urlencoded".

func (*Builder) BodyJSON

func (rb *Builder) BodyJSON(v interface{}) *Builder

BodyJSON sets the Builder's request body to the marshaled JSON. It also sets ContentType to "application/json".

func (*Builder) BodyReader

func (rb *Builder) BodyReader(r io.Reader) *Builder

BodyReader sets the Builder's request body to r.

func (*Builder) CheckContentType added in v0.21.2

func (rb *Builder) CheckContentType(ct string) *Builder

CheckContentType adds a validator for the content type of a response.

func (*Builder) CheckStatus

func (rb *Builder) CheckStatus(acceptStatuses ...int) *Builder

CheckStatus adds a validator for status code of a response.

func (*Builder) Client

func (rb *Builder) Client(cl *http.Client) *Builder

Client sets the http.Client to use for requests. If nil, it uses http.DefaultClient.

func (*Builder) Clone

func (rb *Builder) Clone() *Builder

Clone creates a new Builder suitable for independent mutation.

func (*Builder) ContentType

func (rb *Builder) ContentType(ct string) *Builder

ContentType sets the Content-Type header on a request.

func (*Builder) Do

func (rb *Builder) Do(req *http.Request) (err error)

Do calls the underlying http.Client and validates and handles any resulting response. The response body is closed after all validators and the handler run.

func (*Builder) Fetch

func (rb *Builder) Fetch(ctx context.Context) (err error)

Fetch builds a request, sends it, and handles the response.

func (*Builder) Get

func (rb *Builder) Get() *Builder

Get sets HTTP method to GET.

func (*Builder) GetBody

func (rb *Builder) GetBody(src BodyGetter) *Builder

GetBody sets the BodySource for a request. It implicitly sets method to POST.

func (*Builder) Handle

func (rb *Builder) Handle(h ResponseHandler) *Builder

Handle sets the response handler for a Builder. To use multiple handlers, use ChainHandlers.

func (*Builder) Header

func (rb *Builder) Header(key, value string) *Builder

Header sets a header on a request. It overwrites the value of existing keys.

func (*Builder) Host

func (rb *Builder) Host(host string) *Builder

Host sets the host for a request. It overrides the URL function.

func (*Builder) Hostf added in v0.21.2

func (rb *Builder) Hostf(format string, a ...interface{}) *Builder

Hostf calls Host with fmt.Sprintf.

func (*Builder) Method

func (rb *Builder) Method(method string) *Builder

Method sets the HTTP method for a request.

func (*Builder) Param

func (rb *Builder) Param(key, value string) *Builder

Param sets a query parameter on a request. It overwrites the value of existing keys.

func (*Builder) Path

func (rb *Builder) Path(path string) *Builder

Path sets the path for a request. It overrides the URL function.

func (*Builder) Pathf added in v0.21.2

func (rb *Builder) Pathf(format string, a ...interface{}) *Builder

Pathf calls Path with fmt.Sprintf.

func (*Builder) Post

func (rb *Builder) Post() *Builder

Post sets HTTP method to POST.

func (*Builder) Put

func (rb *Builder) Put() *Builder

Put sets HTTP method to PUT.

func (*Builder) Request

func (rb *Builder) Request(ctx context.Context) (req *http.Request, err error)

Request builds a new http.Request with its context set.

func (*Builder) ToBufioReader

func (rb *Builder) ToBufioReader(f func(r *bufio.Reader) error) *Builder

ToBufioReader sets the Builder to call a callback with the response body wrapped in a bufio.Reader.

func (*Builder) ToBytesBuffer

func (rb *Builder) ToBytesBuffer(buf *bytes.Buffer) *Builder

ToBytesBuffer sets the Builder to write the response body to the provided bytes.Buffer.

func (*Builder) ToJSON

func (rb *Builder) ToJSON(v interface{}) *Builder

ToJSON sets the Builder to decode a response as a JSON object

func (*Builder) ToString

func (rb *Builder) ToString(sp *string) *Builder

ToString sets the Builder to write the response body to the provided string pointer.

func (*Builder) UserAgent

func (rb *Builder) UserAgent(s string) *Builder

UserAgent sets the User-Agent header.

type ResponseHandler

type ResponseHandler = func(*http.Response) error

ResponseHandler is used to validate or handle the response to a request.

DefaultValidator is the validator applied by Builder unless otherwise specified.

func ChainHandlers

func ChainHandlers(handlers ...ResponseHandler) ResponseHandler

ChainHandlers allows for the composing of validators or response handlers.

func CheckContentType added in v0.21.2

func CheckContentType(ct string) ResponseHandler

CheckContentType validates that a response has the given content type.

func CheckStatus

func CheckStatus(acceptStatuses ...int) ResponseHandler

CheckStatus validates the response has an acceptable status code.

func ToBufioReader

func ToBufioReader(f func(r *bufio.Reader) error) ResponseHandler

ToBufioReader takes a callback which wraps the response body in a bufio.Reader.

func ToBytesBuffer

func ToBytesBuffer(buf *bytes.Buffer) ResponseHandler

ToBytesBuffer writes the response body to the provided bytes.Buffer.

func ToJSON

func ToJSON(v interface{}) ResponseHandler

ToJSON decodes a response as a JSON object.

func ToString

func ToString(sp *string) ResponseHandler

ToString writes the response body to the provided string pointer.

type StatusError

type StatusError struct {
	URL, Status string
	StatusCode  int
}

StatusError is the error type produced by CheckStatus.

func (StatusError) Error

func (se StatusError) Error() string

Error fulfills the error interface.

Jump to

Keyboard shortcuts

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