Categorygithub.com/carlmjohnson/requests
modulepackage
0.24.3
Repository: https://github.com/carlmjohnson/requests.git
Documentation: pkg.go.dev

# README

Requests GoDoc Go Report Card Coverage Status Mentioned in Awesome Go

Requests logo

HTTP requests for Gophers.

The problem: Go's net/http is powerful and versatile, but using it correctly for client requests can be extremely verbose.

The solution: 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.

Requests also comes with tools for building custom http transports, include a request recorder and replayer for testing.

See this note on the canonical project URL.

Features

  • Simplifies HTTP client usage compared to net/http
  • Can't forget to close response body
  • Checks status codes by default
  • Supports context.Context
  • JSON serialization and deserialization helpers
  • Easily manipulate URLs and query parameters
  • Request recording and replaying for tests
  • Customizable transports and validators that are compatible with the standard library and third party libraries
  • No third party dependencies
  • Good test coverage

Examples

Simple GET into a string

code with net/httpcode with requests
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)
var s string
err := requests.
	URL("http://example.com").
	ToString(&s).
	Fetch(ctx)
11+ lines5 lines

POST a raw body

code with net/httpcode with requests
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 {
	// ...
}
err := requests.
	URL("https://postman-echo.com/post").
	BodyBytes([]byte(`hello, world`)).
	ContentType("text/plain").
	Fetch(ctx)
12+ lines5 lines

GET a JSON object

code with net/httpcode with requests
var post placeholder
u, err := url.Parse("https://jsonplaceholder.typicode.com")
if err != nil {
	// ...
}
u.Path = fmt.Sprintf("/posts/%d", 1)
req, err := http.NewRequestWithContext(ctx,
	http.MethodGet, u.String(), 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 {
	// ...
}
err := json.Unmarshal(b, &post)
if err != nil {
	// ...
}
var post placeholder
err := requests.
	URL("https://jsonplaceholder.typicode.com").
	Pathf("/posts/%d", 1).
	ToJSON(&post).
	Fetch(ctx)
18+ lines7 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(ctx)
// net/http equivalent left as an exercise for the reader

Set custom headers for a request

// Set headers
var headers postman
err := requests.
	URL("https://postman-echo.com/get").
	UserAgent("bond/james-bond").
	ContentType("secret").
	Header("martini", "shaken").
	Fetch(ctx)

Easily manipulate URLs and query parameters

u, err := requests.
	URL("https://prod.example.com/get?a=1&b=2").
	Hostf("%s.example.com", "dev1").
	Param("b", "3").
	ParamInt("c", 4).
	URL()
if err != nil { /* ... */ }
fmt.Println(u.String()) // https://dev1.example.com/get?a=1&b=3&c=4

Record and replay responses

// record a request to the file system
var s1, s2 string
err := requests.URL("http://example.com").
	Transport(reqtest.Record(nil, "somedir")).
	ToString(&s1).
	Fetch(ctx)
check(err)

// now replay the request in tests
err = requests.URL("http://example.com").
	Transport(reqtest.Replay("somedir")).
	ToString(&s2).
	Fetch(ctx)
check(err)
assert(s1 == s2) // true

FAQs

See wiki for more details.

Why not just use the standard library HTTP client?

Brad Fitzpatrick, long time maintainer of the net/http package, wrote an extensive list of problems with the standard library HTTP client. His four main points (ignoring issues that can't be resolved by a wrapper around the standard library) are:

  • Too easy to not call Response.Body.Close.
  • Too easy to not check return status codes
  • Context support is oddly bolted on
  • Proper usage is too many lines of boilerplate

Requests solves these issues by always closing the response body, checking status codes by default, always requiring a context.Context, and simplifying the boilerplate with a descriptive UI based on fluent method chaining.

Why requests and not some other helper library?

There are two major flaws in other libraries as I see it. One is that in other libraries support for context.Context tends to be bolted on if it exists at all. Two, many hide the underlying http.Client in such a way that it is difficult or impossible to replace or mock out. Beyond that, I believe that none have achieved the same core simplicity that the requests library has.

How do I just get some JSON?

var data SomeDataType
err := requests.
	URL("https://example.com/my-json").
	ToJSON(&data).
	Fetch(ctx)

How do I post JSON and read the response JSON?

body := MyRequestType{}
var resp MyResponseType
err := requests.
	URL("https://example.com/my-json").
	BodyJSON(&body).
	ToJSON(&resp).
	Fetch(ctx)

How do I just save a file to disk?

It depends on exactly what you need in terms of file atomicity and buffering, but this will work for most cases:

err := requests.
	URL("http://example.com").
	ToFile("myfile.txt").
	Fetch(ctx)

For more advanced use case, use ToWriter.

How do I save a response to a string?

var s string
err := requests.
	URL("http://example.com").
	ToString(&s).
	Fetch(ctx)

How do I validate the response status?

By default, if no other validators are added to a builder, requests will check that the response is in the 2XX range. If you add another validator, you can add builder.CheckStatus(200) or builder.AddValidator(requests.DefaultValidator) to the validation stack.

To disable all response validation, run builder.AddValidator(nil).

Contributing

Please create a discussion before submitting a pull request for a new feature.

# Packages

Package reqhtml contains utilities for sending and receiving x/net/html objects.
Package reqtest contains helpers for writing tests of HTTP clients and servers.
Package reqxml contains utilities for sending and receiving XML.

# Functions

BodyBytes is a BodyGetter that returns the provided raw bytes.
BodyFile is a BodyGetter that reads the provided file path.
BodyForm is a BodyGetter that builds an encoded form body.
BodyJSON is a [BodySerializer] that uses [JSONSerializer] to marshal the object.
BodyMultipart returns a Config that uses a multipart.Writer for the request body.
BodyReader is a BodyGetter that returns an io.Reader.
BodySerializer is a BodyGetter that uses the provided [Serializer] to build the body of a request from v.
BodyWriter is a BodyGetter that pipes writes into a request body.
Caching returns an http.RoundTripper that attempts to read its responses from text files in basepath.
ChainHandlers allows for the composing of validators or response handlers.
CheckContentType validates that a response has one of the given content type headers.
CheckPeek wraps the body of a response in a bufio.Reader and gives f a peek at the first n bytes for validation.
CheckStatus validates the response has an acceptable status code.
CopyHeaders copies the response headers to h.
DoerTransport converts a Doer into a Transport.
ErrorJSON is a ValidatorHandler that applies DefaultValidator and decodes the response as a JSON object if the DefaultValidator check fails.
ErrorTransport always returns the specified error instead of connecting.
GzipConfig writes a gzip stream to its request body using a callback.
HasStatusErr returns true if err is a ResponseError caused by any of the codes given.
LogTransport returns a wrapped http.RoundTripper that calls fn with details when a response has finished.
MaxFollow returns a CheckRedirectPolicy that follows a maximum of n redirects.
New creates a new Builder suitable for method chaining by applying the specified Configs.
NewCookieJar returns a cookie jar using the standard public suffix list.
PermitURLTransport returns a wrapped http.RoundTripper that rejects any requests whose URL doesn't match the provided regular expression string.
Record returns an http.RoundTripper that writes out its requests and their responses to text files in basepath.
Replay returns an http.RoundTripper that reads its responses from text files in basepath.
ReplayFS returns an http.RoundTripper that reads its responses from text files in the fs.FS.
ReplayString returns an http.RoundTripper that always responds with a request built from rawResponse.
TestServerConfig returns a Config which sets the Builder's BaseURL to s.URL and the Builder's Client to s.Client().
ToBufioReader takes a callback which wraps the response body in a bufio.Reader.
ToBufioScanner takes a callback which wraps the response body in a bufio.Scanner.
ToBytesBuffer writes the response body to the provided bytes.Buffer.
ToDeserializer decodes a response into v using a [Deserializer].
ToFile writes the response body at the provided file path.
ToHTML parses the page with x/net/html.Parse.
ToJSON decodes a response as a JSON object.
ToString writes the response body to the provided string pointer.
ToWriter copies the response body to w.
URL creates a new Builder suitable for method chaining.
UserAgentTransport returns a wrapped http.RoundTripper that sets the User-Agent header on requests to s.
ValidatorHandler composes a Validator and a Handler.

# Constants

handler error.
error building the request.
error connecting.
error building URL.
validator error.

# Variables

DefaultValidator is the validator applied by Builder unless otherwise specified.
No description provided by the author
JSONDeserializer is used by ToJSON and Builder.ToJSON.
JSONSerializer is used by BodyJSON and Builder.BodyJSON.
NoFollow is a CheckRedirectPolicy that does not follow redirects.
ToHeaders is an alias for backwards compatibility.

# Structs

Builder is a convenient way to build, send, and handle HTTP requests.

# Type aliases

BodyGetter provides a Builder with a source for a request body.
CheckRedirectPolicy is a function suitable for use as CheckRedirect on an http.Client.
Config allows Builder to be extended by setting several options at once.
Deserializer is a function that can read data in some format and store the result in v.
ErrorKind indicates where an error was returned in the process of building, validating, and handling a request.
ResponseError is the error type produced by CheckStatus and CheckContentType.
ResponseHandler is used to validate or handle the response to a request.
RoundTripFunc is an adaptor to use a function as an http.RoundTripper.
Serializer is a function that can convert arbitrary data to bytes in some format.
Transport is an alias of http.RoundTripper for documentation purposes.