remote

package module
v0.21.0 Latest Latest
Warning

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

Go to latest
Published: Jun 22, 2026 License: Apache-2.0 Imports: 15 Imported by: 22

README

REMOTE 🏝

GoDoc Version Build Status Go Report Card Codecov

Crazy Simple, Chainable HTTP Client for Go

Remote is a paper-thin wrapper for Go's HTTP library that gives you sensible defaults, a chainable API with modern conveniences, and full control of your HTTP requests. It's a fast, easy way to make an HTTP call in Go — and it is hardened against SSRF by default.

Inspired by Brandon Romano's Wrecker. Thanks Brandon!

Get data from an HTTP server
// Structure to read the remote data into
users := []struct {
    ID       string
    Name     string
    Username string
    Email    string
}{}

// Get data from a remote server
err := remote.Get("https://jsonplaceholder.typicode.com/users").
    Result(&users).
    Send()
Post/Put/Patch/Delete data to an HTTP server
// Data to send to the remote server
user := map[string]string{
    "id":    "ABC123",
    "name":  "Sarah Connor",
    "email": "sarah@sky.net",
}

// Structure to read the response into
response := map[string]string{}

// Post data to the remote server
err := remote.Post("https://example.com/post-service").
    JSON(user).         // encode the user object into the request body as JSON
    Result(&response).  // parse a successful response into this structure
    Send()
Handling HTTP Errors

Web services represent errors in many ways. Some return only an HTTP status code; others return a structured document in the response body. Remote handles both. Use .Result() for the success body and .Error() for the failure body — Send() returns a non-nil error whenever the response status is outside the 200–299 range, and populates whichever object matches the outcome.

success := SuccessResponse{} // shape defined by the remote service
failure := ErrorResponse{}   // shape defined by the remote service

err := remote.Get("https://example.com/service-that-might-error").
    Result(&success).
    Error(&failure).
    Send()

// Send returns an error IF the HTTP status is not 2xx.
if err != nil {
    // `failure` is populated with the error body from the remote service.
    return err
}

// Fall through means success: `success` is populated.

Security

Remote is built for calling untrusted, user-supplied URLs safely. These guards are on by default.

  • Private IPs are blocked. By default the client refuses to connect to loopback, private, and link-local addresses — defending against SSRF. The check lives in the dialer and re-runs on every redirect hop, so it is safe against DNS rebinding. Call .AllowPrivateIPs(true) to opt out (e.g. for localhost or internal services).
  • Host allow-listing. .AllowHosts("example.com", ...) restricts a transaction to specific hosts. The list is re-checked on every redirect, so an allow-listed server cannot redirect you somewhere unexpected.
  • Response size is capped at 1GB by default, preventing a hostile server from exhausting memory. Tune it with .MaxResponseSize(n).
  • Redirects are capped at 5 hops.
  • Requests are time-bounded. Without a context, a one-minute timeout applies. Supply your own deadline or cancellation with .WithContext(ctx).
err := remote.Get(userSuppliedURL).
    AllowHosts("api.trusted.com").
    MaxResponseSize(10 * 1024 * 1024). // 10MB
    WithContext(ctx).
    Result(&data).
    Send()

Options

Options modify a request before it is sent, or the response after it returns. Add them with .With(...). The options subpackage ships a library of common ones.

import "github.com/benpate/remote/options"

err := remote.Get("https://jsonplaceholder.typicode.com/users").
    With(options.BearerAuth(myAccessToken)).
    With(options.UserAgent("my-app/1.0")).
    Result(&users).
    Send()

See the options README for the full list. An Option exposes three hooks — BeforeRequest, ModifyRequest, and AfterRequest — so you can write your own; the included options are short and make good templates.

Custom Transport

.WithRoundTripper(...) wraps the SSRF-hardened base transport with your own middleware (for caching, instrumentation, custom headers, etc.). Your middleware receives the base transport as next and must delegate to it to perform the request — keeping the private-IP guard underneath.

err := remote.Get("https://example.com").
    WithRoundTripper(func(next http.RoundTripper) http.RoundTripper {
        return myCachingTransport{next: next}
    }).
    Send()

Note that if your middleware short-circuits and returns a response without delegating to next (e.g. a cache hit), no dial happens — and therefore neither SSRF guard runs. That is by design for caching, but worth knowing when the source URL is untrusted.

Pull Requests Welcome

Original versions of this library have been used in production on commercial applications for years, and have helped speed up development for everyone involved.

I'm open sourcing this library, and others, with hopes that you'll also benefit from an easy HTTP library.

Please use GitHub to make suggestions, pull requests, and enhancements. We're all in this together! 🏝

Documentation

Overview

Package remote provides a simple and clean API for making HTTP requests to remote servers.

Index

Constants

View Source
const Accept = "Accept"

Accept is the string used in the HTTP header to request a response be encoded as a MIME type

View Source
const ContentType = "Content-Type"

ContentType is the string used in the HTTP header to designate a MIME type

View Source
const ContentTypeActivityPub = "application/activity+json"

ContentTypeActivityPub is the standard MIME type for ActivityPub content

View Source
const ContentTypeAtomXML = "application/atom+xml"

ContentTypeAtomXML is the standard MIME Type for an Atom RSS feed

View Source
const ContentTypeForm = "application/x-www-form-urlencoded"

ContentTypeForm is the standard MIME Type for Form encoded content

View Source
const ContentTypeHTML = "text/html"

ContentTypeHTML is the standard MIME type for HTML content

View Source
const ContentTypeJSON = "application/json"

ContentTypeJSON is the standard MIME Type for JSON content

View Source
const ContentTypeJSONFeed = "application/feed+json"

ContentTypeJSONFeed is the standard MIME Type for JSON Feed content https://en.wikipedia.org/wiki/JSON_Feed

View Source
const ContentTypeJSONLD = "application/ld+json"

ContentTypeJSONLD is the standard MIME Type for JSON-LD content https://en.wikipedia.org/wiki/JSON-LD

View Source
const ContentTypeJSONResourceDescriptor = "application/jrd+json"

ContentTypeJSONResourceDescriptor is the standard MIME Type for JSON Resource Descriptor content which is used by WebFinger: https://datatracker.ietf.org/doc/html/rfc7033#section-10.2

View Source
const ContentTypePlain = "text/plain"

ContentTypePlain is the default plaintext MIME type

View Source
const ContentTypeRSSXML = "application/rss+xml"

ContentTypeRSSXML is the standard MIME Type for a RSS feed

View Source
const ContentTypeXML = "application/xml"

ContentTypeXML is the standard MIME Type for XML content

View Source
const UserAgent = "User-Agent"

UserAgent is the string used in the HTTP header to identify the client making the request

Variables

This section is empty.

Functions

This section is empty.

Types

type Option added in v0.12.0

type Option struct {

	// BeforeRequest is called before an http.Request is generated. It can be used to
	// modify Transaction values before they are assembled into an http.Request object.
	BeforeRequest func(*Transaction) error

	// ModifyRequest is called after an http.Request has been generated, but before it is sent to the
	// remote server. It can be used to modify the request, or to replace it entirely.
	// If it returns a non-nil http.Response, then that is used INSTEAD OF calling the remote server.
	// If it returns a nil http.Response, then the request is sent to the remote server as normal.
	ModifyRequest func(*Transaction, *http.Request) *http.Response

	// AfterRequest is executed after an http.Response has been received from the remote server, but before it is
	// parsed and returned to the calling application.
	AfterRequest func(*Transaction, *http.Response) error
}

Option is a decorator that can modify the request before it is sent to the remote HTTP server, or modify the response after it is returned by the remote HTTP server.

func Options added in v0.18.1

func Options(values ...any) []Option

Options extracts valid remote.Option values from a list of `any` values.

type Transaction

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

Transaction represents a single HTTP request/response to a remote HTTP server.

func Delete

func Delete(url string) *Transaction

Delete creates a new HTTP request to the designated URL, using the DELETE method.

func Get

func Get(url string) *Transaction

Get creates a new HTTP request to the designated URL, using the GET method

func New added in v0.16.0

func New() *Transaction

New returns a fully initialized Transaction object with default settings.

func Patch

func Patch(url string) *Transaction

Patch creates a new HTTP request to the designated URL, using the PATCH method

func Post

func Post(url string) *Transaction

Post creates a new HTTP request to the designated URL, using the POST method

func Put

func Put(url string) *Transaction

Put creates a new HTTP request to the designated URL, using the PUT method

func (*Transaction) Accept added in v0.10.1

func (t *Transaction) Accept(contentTypes ...string) *Transaction

Accept sets the Content-Type header of the HTTP request.

func (*Transaction) AllowHosts added in v0.20.0

func (t *Transaction) AllowHosts(hosts ...string) *Transaction

AllowHosts restricts this transaction to the named hosts. When set, Send returns an error before contacting the server if the request URL's host is not in the list. This guards against requests to unexpected servers, for instance when the URL is user-supplied. Matching is case-insensitive.

func (*Transaction) AllowPrivateIPs added in v0.20.0

func (t *Transaction) AllowPrivateIPs(value bool) *Transaction

AllowPrivateIPs controls whether the transaction may connect to non-public IP addresses (loopback, private, link-local, etc.). The default is FALSE, so such addresses are blocked to guard against SSRF: Send returns an error if the request (or any redirect) resolves to one. Set it to TRUE to permit them — for instance, when intentionally calling an internal or localhost service.

func (*Transaction) Body

func (t *Transaction) Body(value string) *Transaction

Body sets the request body, to be encoded as plain text

func (*Transaction) ContentType

func (t *Transaction) ContentType(value string) *Transaction

ContentType sets the Content-Type header of the HTTP request.

func (*Transaction) Delete added in v0.16.0

func (t *Transaction) Delete(url string) *Transaction

Delete assigns the HTTP method and URL for this transaction.

func (*Transaction) Error added in v0.12.0

func (t *Transaction) Error(object any) *Transaction

Error sets the object for parsing HTTP error responses

func (*Transaction) Form

func (t *Transaction) Form(name string, value string) *Transaction

Form adds a name/value pair to the form data to be sent to the remote server.

func (*Transaction) Get added in v0.16.0

func (t *Transaction) Get(url string) *Transaction

Get assigns the HTTP method and URL for this transaction.

func (*Transaction) Header

func (t *Transaction) Header(name string, value string) *Transaction

Header sets a designated header value in the HTTP request.

func (*Transaction) JSON

func (t *Transaction) JSON(value any) *Transaction

JSON sets the request body, to be encoded as JSON.

func (*Transaction) MarshalJSON added in v0.16.3

func (t *Transaction) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface, which writes the Transaction object to a JSON string.

func (*Transaction) MarshalMap added in v0.16.3

func (t *Transaction) MarshalMap() map[string]any

MarshalMap converts a Transaction object into a map[string]any

func (*Transaction) MaxResponseSize added in v0.20.0

func (t *Transaction) MaxResponseSize(bytes int64) *Transaction

MaxResponseSize sets the maximum number of bytes that will be read from the response body. A response larger than this causes Send to return an error, preventing an untrusted server from exhausting memory. The default is 1GB. A value of zero or less restores the default.

func (*Transaction) Method

func (t *Transaction) Method(method string) *Transaction

Method assigns the HTTP method for this transaction.

func (*Transaction) Patch added in v0.16.0

func (t *Transaction) Patch(url string) *Transaction

Patch assigns the HTTP method and URL for this transaction.

func (*Transaction) Post added in v0.16.0

func (t *Transaction) Post(url string) *Transaction

Post assigns the HTTP method and URL for this transaction.

func (*Transaction) Put added in v0.16.0

func (t *Transaction) Put(url string) *Transaction

Put assigns the HTTP method and URL for this transaction.

func (*Transaction) Query

func (t *Transaction) Query(name string, value string) *Transaction

Query sets a name/value pair in the URL query string.

func (*Transaction) RequestBody added in v0.12.0

func (t *Transaction) RequestBody() ([]byte, error)

RequestBody returns the serialized body of the request as a slice of bytes.

func (*Transaction) RequestURL added in v0.12.0

func (t *Transaction) RequestURL() string

RequestURL returns the full URL for this request, including query string parameters.

func (*Transaction) Response

func (t *Transaction) Response() *http.Response

Response returns the original HTTP response object.

func (*Transaction) ResponseBody added in v0.12.0

func (t *Transaction) ResponseBody() ([]byte, error)

ResponseBody returns the original response body, as a byte array. This method replaces the original body reader, meaning that it can be called multiple times without error.

func (*Transaction) ResponseBodyReader added in v0.12.0

func (t *Transaction) ResponseBodyReader() io.Reader

ResponseBodyReader returns an io.Reader for the response body.

func (*Transaction) ResponseContentType added in v0.12.0

func (t *Transaction) ResponseContentType() string

ResponseContentType returns the Content-Type header of the response.

func (*Transaction) ResponseHeader added in v0.12.0

func (t *Transaction) ResponseHeader() http.Header

ResponseHeader returns the HTTP response header.

func (*Transaction) ResponseStatusCode added in v0.12.0

func (t *Transaction) ResponseStatusCode() int

ResponseStatusCode returns the HTTP status code of the response.

func (*Transaction) Result added in v0.12.0

func (t *Transaction) Result(object any) *Transaction

Result sets the object for parsing HTTP success responses

func (*Transaction) Send

func (t *Transaction) Send() error

Send executes the transaction, sending the request to the remote server.

func (*Transaction) URL added in v0.16.3

func (t *Transaction) URL(url string) *Transaction

URL assigns the URL for this transaction.

func (*Transaction) UnmarshalJSON added in v0.16.3

func (t *Transaction) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface, which reads a Transaction object from a JSON string.

func (*Transaction) UnmarshalMap added in v0.16.3

func (t *Transaction) UnmarshalMap(value map[string]any) error

UnmarshalMap populates a Transaction object from a map[string]any

func (*Transaction) UserAgent added in v0.12.0

func (t *Transaction) UserAgent(value string) *Transaction

UserAgent sets the User-Agent header of the HTTP request.

func (*Transaction) With added in v0.16.0

func (t *Transaction) With(options ...Option) *Transaction

With lets you add remote.Options to the transaction. Options modify transaction data before and after it is sent to the remote server.

func (*Transaction) WithContext added in v0.20.0

func (t *Transaction) WithContext(ctx context.Context) *Transaction

WithContext attaches a context to the transaction, used to cancel the request or apply a deadline. If no context is set, a background context with a default one-minute timeout is used.

func (*Transaction) WithRoundTripper added in v0.20.0

func (t *Transaction) WithRoundTripper(wrap func(next http.RoundTripper) http.RoundTripper) *Transaction

WithRoundTripper wraps the transaction's SSRF-hardened base transport with the given middleware, letting callers add behavior such as caching or custom headers while keeping the private-IP guard underneath. The middleware receives the base transport as "next" and must delegate to it to perform the request.

func (*Transaction) XML

func (t *Transaction) XML(value any) *Transaction

XML sets the request body, to be encoded as XML.

Directories

Path Synopsis
Package options is a library of common remote.Options that are useful for modifying the behavior of a remote.Transaction.
Package options is a library of common remote.Options that are useful for modifying the behavior of a remote.Transaction.

Jump to

Keyboard shortcuts

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