Documentation
¶
Overview ¶
Package requester is a Go library for building and sending HTTP requests. It's a thin wrapper around the http package, which makes it a little easier to create and send requests, and to handle responses.
Requester revolves around the use of functional Options. Options can be be used to configure aspects of the request, like headers, query params, the URL, etc. Options can also configure the client used to send requests.
The central functions are Request(), Send(), and Receive():
// Create a request
req, err := requester.Request(
requester.JSON(),
requester.Get("http://api.com/users/bob"),
)
// Create and send a request
resp, err := requester.Send(
requester.JSON(),
requester.Non2XXResponseAsError(),
requester.Get("http://api.com/users/bob"),
)
// Create and send a request, and handle the response
var user User
resp, body, err := requester.Receive(&user,
requester.JSON(),
requester.Non2XXResponseAsError(),
requester.BasicAuth("user", "password"),
requester.Client(httpclient.NoRedirects()),
requester.DumpToStandardOut(),
requester.Get("http://api.com/users/bob"),
)
// Create a reusable Requester instance
reqr, err := requester.New(
requester.JSON(),
requester.Non2XXResponseAsError(),
requester.BasicAuth("user", "password"),
requester.Client(httpclient.NoRedirects()),
requester.DumpToStandardOut(),
)
// Requester instances have the same main methods as the package
req, err := reqr.Request(
requester.Get("http://api.com/users/bob")
)
resp, err := reqr.Send(
requester.Get("http://api.com/users/bob")
)
resp, body, err := reqr.Receive(&user,
requester.Get("http://api.com/users/bob")
)
There are also *Context() variants as well:
ctx = context.WithTimeout(ctx, 10 * time.Second)
requester.RequestContext(ctx, requester.Get("http://api.com/users/bob"))
requester.SendContext(ctx, requester.Get("http://api.com/users/bob"))
requester.ReceiveContext(ctx, &into, requester.Get("http://api.com/users/bob"))
The attributes of the Requester control how it creates and sends requests, and how it handles responses:
type Requester struct {
// These are copied directly into requests, if they contain
// a non-zero value
Method string
URL *url.URL
Header http.Header
GetBody func() (io.ReadCloser, error)
ContentLength int64
TransferEncoding []string
Close bool
Host string
Trailer http.Header
// these are handled specially, see below
QueryParams url.Values
Body interface{}
Marshaler Marshaler
// these configure how to send requests
Doer Doer
Middleware []Middleware
// this configures response handling
Unmarshaler Unmarshaler
}
These attributes can be modified directly, by assignment, or by applying Options. Options are simply functions which modify these attributes. For example:
reqr, err := requester.New(
requester.Method("POST),
)
is equivalent to
reqr := &requester.Requester{
Method: "POST",
}
New Requesters can be constructed with New(...Options):
reqs, err := requester.New(
requester.Get("http://api.server/resources/1"),
requester.JSON(),
requester.Accept(requester.MediaTypeJSON)
)
Additional options can be applied with Apply():
err := reqs.Apply(
requester.Method("POST"),
requester.Body(bodyStruct),
)
...or the Requester's members can just be set directly:
reqs.Method = "POST" reqs.Body = bodyStruct
Requesters can be cloned, creating a copy which can be further configured:
base, err := requester.New(
requester.URL("https://api.com"),
requester.JSON(),
requester.Accept(requester.MediaTypeJSON),
requester.BearerAuth(token),
)
clone = base.Clone()
err = clone.Apply(
requester.Get("resources/1"),
)
With(...Option) combines Clone() and Apply(...Option):
clone, err := base.With(
requester.Get("resources/1"),
)
HTTP Client Options ¶
The HTTP client used to execute requests can also be customized with Options:
import "github.com/gemalto/requester/httpclient"
requester.Send(
requester.Get("https://api.com"),
requester.Client(httpclient.SkipVerify()),
)
"github.com/gemalto/requester/httpclient" is a standalone package for constructing and configuring http.Clients. The requester.Client(...httpclient.Option) option constructs a new HTTP client and installs it into Requester.Doer.
Query Params ¶
Requester.QueryParams will be merged into any query parameters encoded into the URL. For example:
reqs, _ := requester.New(
requester.URL("http://test.com?color=red"),
)
reqs.QueryParams = url.Values("flavor":[]string{"vanilla"})
r, _ := reqs.Request()
r.URL.String()
// Output: http://test.com?color=red&flavor=vanilla
The QueryParams() option can take a map[string]string, a map[string]interface{}, a url.Values, or a struct. Structs are marshaled into url.Values using "github.com/google/go-querystring":
type Params struct {
Color string `url:"color"`
}
reqs, _ := requester.New(
requester.URL("http://test.com"),
requester.QueryParams(
Params{Color:"blue"},
map[string][]string{"flavor":[]string{"vanilla"}},
map[string]string{"temp":"hot"},
url.Values{"speed":[]string{"fast"}},
),
requester.QueryParam("volume","load"),
)
r, _ := reqs.Request()
r.URL.String()
// Output: http://test.com?color=blue,flavor=vanilla,temp=hot,speed=fast,volume=loud
Body ¶
If Requester.Body is set to a string, []byte, or io.Reader, the value will be used directly as the request body:
req, _ := requester.Request(
requester.Post("http://api.com"),
requester.ContentType(requester.MediaTypeJSON),
requester.Body(`{"color":"red"}`),
)
httputil.DumpRequest(req, true)
// POST / HTTP/1.1
// Host: api.com
// Content-Type: application/json
//
// {"color":"red"}
If Body is any other value, it will be marshaled into the body, using the Requester.Marshaler:
type Resource struct {
Color string `json:"color"`
}
req, _ := requester.Request(
requester.Post("http://api.com"),
requester.Body(Resource{Color:"red"}),
)
httputil.DumpRequest(req, true)
// POST / HTTP/1.1
// Host: api.com
// Content-Type: application/json
//
// {"color":"red"}
Note the default marshaler is JSON, and sets the Content-Type header.
Receive ¶
Receive() handles the response as well:
type Resource struct {
Color string `json:"color"`
}
var res Resource
resp, body, err := requester.Receive(&res,
requester.Get("http://api.com/resources/1",
)
fmt.Println(body) // {"color":"red"}
The body of the response is returned. Even in cases where an error is returned, the body and the response will be returned as well, if available. This is helpful when middleware which validates aspects of the response generates an error, but the calling code still needs to inspect the contents of the body (e.g. for an error message).
If the first argument is not nil, the body will also be unmarshaled into that value. By default, the unmarshaler will use the response's Content-Type header to determine how to unmarshal the response body into a struct. This can be customized by setting Requester.Unmarshaler:
reqs.Unmarshaler = &requester.XMLMarshaler(Indent:true) // via assignment reqs.Apply(requester.WithUnmarshaler(&requester.XMLMarshaler(Indent:true))) // or via an Option
Doer and Middleware ¶
Requester uses a Doer to execute requests, which is an interface. By default, http.DefaultClient is used, but this can be replaced by a customize client, or a mock Doer:
reqs.Doer = requester.DoerFunc(func(req *http.Request) (*http.Response, error) {
return &http.Response{}
})
Requester itself is a Doer, so it can be nested in other Requester or composed with other packages that support Doers.
You can also install middleware into Requester, which can intercept the request and response:
mw := func(next requester.Doer) requester.Doer {
return requester.DoerFunc(func(req *http.Request) (*http.Response, error) {
fmt.Println(httputil.DumpRequest(req, true))
resp, err := next(req)
if err == nil {
fmt.Println(httputil.DumpResponse(resp, true))
}
return resp, err
})
}
reqs.Middleware = append(reqs.Middleware, mw) // via assignment
reqs.Apply(requester.Use(mw)) // or via option
Example ¶
package main
import (
"fmt"
"github.com/gemalto/requester"
"net/http"
"net/http/httptest"
)
func main() {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
w.Write([]byte(`{"color":"red"}`))
}))
defer s.Close()
resp, body, _ := requester.Receive(
requester.Get(s.URL),
)
fmt.Println(resp.StatusCode)
fmt.Println(string(body))
}
Output: 200 {"color":"red"}
Example (Receive) ¶
package main
import (
"fmt"
"github.com/gemalto/requester"
"net/http"
"net/http/httptest"
)
func main() {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
w.Write([]byte(`{"color":"red"}`))
}))
defer s.Close()
respStruct := struct {
Color string
}{}
requester.Receive(&respStruct,
requester.Get(s.URL),
)
fmt.Println(respStruct.Color)
}
Output: red
Index ¶
- Constants
- Variables
- func ChannelHandler() (chan<- *http.Response, http.Handler)
- func MockHandler(statusCode int, options ...Option) http.Handler
- func MockResponse(statusCode int, options ...Option) *http.Response
- func Receive(successV interface{}, opts ...Option) (*http.Response, []byte, error)
- func ReceiveContext(ctx context.Context, successV interface{}, opts ...Option) (*http.Response, []byte, error)
- func Request(opts ...Option) (*http.Request, error)
- func RequestContext(ctx context.Context, opts ...Option) (*http.Request, error)
- func Send(opts ...Option) (*http.Response, error)
- func SendContext(ctx context.Context, opts ...Option) (*http.Response, error)
- type Doer
- type DoerFunc
- type FormMarshaler
- type Inspector
- type JSONMarshaler
- type MarshalFunc
- type Marshaler
- type Middleware
- type MultiUnmarshaler
- type Option
- func Accept(accept string) Option
- func AddHeader(key, value string) Option
- func BasicAuth(username, password string) Option
- func BearerAuth(token string) Option
- func Body(body interface{}) Option
- func Client(opts ...httpclient.Option) Option
- func ContentType(contentType string) Option
- func Delete(paths ...string) Option
- func DeleteHeader(key string) Option
- func Form() Option
- func Get(paths ...string) Option
- func Head(paths ...string) Option
- func Header(key, value string) Option
- func Host(host string) Option
- func JSON(indent bool) Option
- func Method(m string, paths ...string) Option
- func Patch(paths ...string) Option
- func Post(paths ...string) Option
- func Put(paths ...string) Option
- func QueryParam(k, v string) Option
- func QueryParams(queryStructs ...interface{}) Option
- func RelativeURL(paths ...string) Option
- func URL(rawurl string) Option
- func Use(m ...Middleware) Option
- func WithDoer(d Doer) Option
- func WithMarshaler(m Marshaler) Option
- func WithUnmarshaler(m Unmarshaler) Option
- func XML(indent bool) Option
- type OptionFunc
- type Requester
- func (r *Requester) Apply(opts ...Option) error
- func (r *Requester) Clone() *Requester
- func (r *Requester) Do(req *http.Request) (*http.Response, error)
- func (r *Requester) Headers() http.Header
- func (r *Requester) MustApply(opts ...Option)
- func (r *Requester) Params() url.Values
- func (r *Requester) Receive(into interface{}, opts ...Option) (resp *http.Response, body []byte, err error)
- func (r *Requester) ReceiveContext(ctx context.Context, into interface{}, opts ...Option) (resp *http.Response, body []byte, err error)
- func (r *Requester) Request(opts ...Option) (*http.Request, error)
- func (r *Requester) RequestContext(ctx context.Context, opts ...Option) (*http.Request, error)
- func (r *Requester) Send(opts ...Option) (*http.Response, error)
- func (r *Requester) SendContext(ctx context.Context, opts ...Option) (*http.Response, error)
- func (r *Requester) Trailers() http.Header
- func (r *Requester) With(opts ...Option) (*Requester, error)
- type UnmarshalFunc
- type Unmarshaler
- type XMLMarshaler
Examples ¶
Constants ¶
const ( HeaderAccept = "Accept" HeaderContentType = "Content-Type" HeaderAuthorization = "Authorization" MediaTypeJSON = "application/json" MediaTypeXML = "application/xml" MediaTypeForm = "application/x-www-form-urlencoded" MediaTypeOctetStream = "application/octet-stream" MediaTypeTextPlain = "text/plain" MediaTypeMultipart = "multipart/mixed" MediaTypeMultipartForm = "multipart/form-data" )
HTTP constants.
Variables ¶
var DefaultRequester = Requester{}
DefaultRequester is the singleton used by the package-level Request/Send/Receive functions.
Functions ¶
func ChannelHandler ¶ added in v0.2.0
ChannelHandler returns an http.Handler and an input channel. The Handler returns the http.Responses sent to the channel.
Example ¶
in, h := ChannelHandler()
ts := httptest.NewServer(h)
defer ts.Close()
in <- &http.Response{
StatusCode: 201,
Body: ioutil.NopCloser(strings.NewReader("pong")),
}
resp, body, _ := Receive(URL(ts.URL))
fmt.Println(resp.StatusCode)
fmt.Println(string(body))
Output: 201 pong
func MockHandler ¶ added in v0.2.0
MockHandler returns an http.Handler which returns responses built from the args. The Option arguments are used to build an http.Request, then the header and body of the request are copied into an http.Response object.
Example ¶
h := MockHandler(201,
JSON(false),
Body(map[string]interface{}{"color": "blue"}),
)
ts := httptest.NewServer(h)
defer ts.Close()
resp, body, _ := Receive(URL(ts.URL))
fmt.Println(resp.StatusCode)
fmt.Println(resp.Header.Get(HeaderContentType))
fmt.Println(string(body))
Output: 201 application/json {"color":"blue"}
func MockResponse ¶ added in v0.2.0
MockResponse creates an *http.Response from the Options. Requests and Responses share most of the same fields, so we use the options to build a Request, then copy the values as appropriate into a Response. Useful for created mocked responses for tests.
func ReceiveContext ¶
func ReceiveContext(ctx context.Context, successV interface{}, opts ...Option) (*http.Response, []byte, error)
ReceiveContext does the same as Requester.ReceiveContext(), using the DefaultRequester.
func RequestContext ¶
RequestContext does the same as Requester.RequestContext(), using the DefaultRequester.
Types ¶
type Doer ¶
Doer executes http requests. It is implemented by *http.Client. You can wrap *http.Client with layers of Doers to form a stack of client-side middleware.
func Wrap ¶
func Wrap(d Doer, m ...Middleware) Doer
Wrap applies a set of middleware to a Doer. The returned Doer will invoke the middleware in the order of the arguments.
type DoerFunc ¶
DoerFunc adapts a function to implement Doer
func ChannelDoer ¶ added in v0.2.0
ChannelDoer returns a DoerFunc and a channel. The DoerFunc will return the responses send on the channel.
Example ¶
in, d := ChannelDoer()
in <- &http.Response{
StatusCode: 201,
Body: ioutil.NopCloser(strings.NewReader("pong")),
}
resp, body, _ := Receive(d)
fmt.Println(resp.StatusCode)
fmt.Println(string(body))
Output: 201 pong
func MockDoer ¶ added in v0.2.0
MockDoer creates a mock Doer which returns a mocked response. By default, the mocked response will contain the status code, and typical default values for some standard response fields, like the ProtoXXX fields.
Options can be passed in, which are used to construct a template http.Request. The fields of the template request are copied into the mocked responses (http.Request and http.Response share most fields, so we're leverage the rich set of requester.Options to build the response).
Example ¶
d := MockDoer(201,
JSON(false),
Body(map[string]interface{}{"color": "blue"}),
)
resp, body, _ := Receive(d)
fmt.Println(resp.StatusCode)
fmt.Println(resp.Header.Get(HeaderContentType))
fmt.Println(string(body))
Output: 201 application/json {"color":"blue"}
type FormMarshaler ¶
type FormMarshaler struct{}
FormMarshaler implements Marshaler. It marshals values into URL-Encoded form data.
The value can be either a map[string][]string, map[string]string, url.Values, or a struct with `url` tags.
type Inspector ¶ added in v0.2.0
type Inspector struct {
// The last request sent by the client.
Request *http.Request
// The last response received by the client.
Response *http.Response
// The last client request body
RequestBody *bytes.Buffer
// The last client response body
ResponseBody *bytes.Buffer
}
Inspector is a Requester Option which captures requests and responses. It's useful for inspecting the contents of exchanges in tests.
It not an efficient way to capture bodies, and keeps requests and responses around longer than their intended lifespan, so it should not be used in production code or benchmarks.
func Inspect ¶ added in v0.2.0
Inspect installs and returns an Inspector. The Inspector captures the last request, request body, response and response body. Useful in tests for inspecting traffic.
Example ¶
Inspect returns an Inspector, which captures the traffic to and from a Requester. It's a tool for writing tests.
r := MustNew(
MockDoer(201, Body("pong")),
Header(HeaderAccept, MediaTypeTextPlain),
Body("ping"),
)
i := Inspect(r)
r.Receive(nil)
fmt.Println(i.Request.Header.Get(HeaderAccept))
fmt.Println(i.RequestBody.String())
fmt.Println(i.Response.StatusCode)
fmt.Println(i.ResponseBody.String())
Output: text/plain ping 201 pong
func (*Inspector) Clear ¶ added in v0.2.0
func (i *Inspector) Clear()
Clear clears the inspector's fields.
func (*Inspector) MiddlewareFunc ¶ added in v0.2.1
MiddlewareFunc implements Middleware
type JSONMarshaler ¶
type JSONMarshaler struct {
Indent bool
}
JSONMarshaler implement Marshaler and Unmarshaler. It marshals values to and from JSON. If Indent is true, marshaled JSON will be indented.
r := requester.Requester{
Body: &JSONMarshaler{},
}
type MarshalFunc ¶
MarshalFunc adapts a function to the Marshaler interface.
func (MarshalFunc) Apply ¶ added in v0.2.0
func (f MarshalFunc) Apply(r *Requester) error
Apply implements Option. MarshalFunc can be applied as a requester option, which install itself as the Marshaler.
type Marshaler ¶
Marshaler marshals structs into a []byte, and supplies a matching Content-Type header.
var DefaultMarshaler Marshaler = &JSONMarshaler{}
DefaultMarshaler is used by Requester if Requester.Marshaler is nil.
type Middleware ¶
Middleware can be used to wrap Doers with additional functionality:
loggingMiddleware := func(next Doer) Doer {
return func(req *http.Request) (*http.Response, error) {
logRequest(req)
return next(req)
}
}
Middleware can be applied to a Requester object with the Use() option:
reqs.Apply(requester.Use(loggingMiddleware))
Middleware itself is an Option, so it can also be applied directly:
reqs.Apply(Middleware(loggingMiddleware))
func Dump ¶
func Dump(w io.Writer) Middleware
Dump dumps requests and responses to a writer. Just intended for debugging.
func DumpToLog ¶
func DumpToLog(logf func(a ...interface{})) Middleware
DumpToLog dumps the request and response to a logging function. logf is compatible with fmt.Print(), testing.T.Log, or log.XXX() functions.
Request and response will be logged separately. Though logf takes a variadic arg, it will only be called with one string arg at a time.
func DumpToStandardOut ¶
func DumpToStandardOut() Middleware
DumpToStandardOut dumps requests to os.Stdout.
func ExpectCode ¶ added in v0.2.0
func ExpectCode(code int) Middleware
ExpectCode is middleware which generates an error if the response's status code does not match the expected code.
Example ¶
resp, body, err := Receive(
Get("/profile"),
MockDoer(400, Body("bad format")),
ExpectCode(201),
)
fmt.Println(resp.StatusCode)
fmt.Println(string(body))
fmt.Println(err.Error())
Output: 400 bad format server returned unexpected status code. expected: 201, received: 400
func ExpectSuccessCode ¶ added in v0.2.0
func ExpectSuccessCode() Middleware
ExpectSuccessCode is middleware which generates an error if the response's status code is not between 200 and 299.
Example ¶
resp, body, err := Receive(
Get("/profile"),
MockDoer(400, Body("bad format")),
ExpectSuccessCode(),
)
fmt.Println(resp.StatusCode)
fmt.Println(string(body))
fmt.Println(err.Error())
Output: 400 bad format server returned an unsuccessful status code: 400
type MultiUnmarshaler ¶
type MultiUnmarshaler struct {
// contains filtered or unexported fields
}
MultiUnmarshaler implements Unmarshaler. It uses the value of the Content-Type header in the response to choose between the JSON and XML unmarshalers. If Content-Type is something else, an error is returned.
type Option ¶
type Option interface {
// Apply modifies the Requester argument. The Requester pointer will never be nil.
// Returning an error will stop applying the request of the Options, and the error
// will float up to the original caller.
Apply(*Requester) error
}
Option applies some setting to a Requester object. Options can be passed as arguments to most of Requester' methods.
func BasicAuth ¶
BasicAuth sets the Authorization header to "Basic <encoded username and password>". If username and password are empty, it deletes the Authorization header.
func BearerAuth ¶
BearerAuth sets the Authorization header to "Bearer <token>". If the token is empty, it deletes the Authorization header.
func Client ¶
func Client(opts ...httpclient.Option) Option
Client replaces Requester.Doer with an *http.Client. The client will be created and configured using the `httpclient` package.
func ContentType ¶
ContentType sets the Content-Type header.
func Delete ¶
Delete sets the HTTP method to "DELETE". Optional path arguments will be applied via the RelativeURL option.
func DeleteHeader ¶
DeleteHeader deletes a header key, using Header.Del()
func Form ¶
func Form() Option
Form sets Requester.Marshaler to the FormMarshaler, which marshals the body into form-urlencoded. The FormMarshaler will set the Content-Type header to "application/x-www-form-urlencoded" unless explicitly overwritten.
func Get ¶
Get sets the HTTP method to "GET". Optional path arguments will be applied via the RelativeURL option.
func Head ¶
Head sets the HTTP method to "HEAD". Optional path arguments will be applied via the RelativeURL option.
func JSON ¶
JSON sets Requester.Marshaler to the JSONMarshaler. If the arg is true, the generated JSON will be indented. The JSONMarshaler will set the Content-Type header to "application/json" unless explicitly overwritten.
func Method ¶
Method sets the HTTP method (e.g. GET/DELETE/etc). If path arguments are passed, they will be applied via the RelativeURL option.
func Patch ¶
Patch sets the HTTP method to "PATCH". Optional path arguments will be applied via the RelativeURL option.
func Post ¶
Post sets the HTTP method to "POST". Optional path arguments will be applied via the RelativeURL option.
func Put ¶
Put sets the HTTP method to "PUT". Optional path arguments will be applied via the RelativeURL option.
func QueryParams ¶
func QueryParams(queryStructs ...interface{}) Option
QueryParams adds params to the Requester.QueryParams member. The arguments may be either map[string][]string, map[string]string, url.Values, or a struct. The argument values are merged into Requester.QueryParams, overriding existing values.
If the arg is a struct, the struct is marshaled into a url.Values object using the github.com/google/go-querystring/query package. Structs should tag their members with the "url" tag, e.g.:
type ReqParams struct {
Color string `url:"color"`
}
An error will be returned if marshaling the struct fails.
func RelativeURL ¶
RelativeURL resolves the arg as a relative URL references against the current URL, using the standard lib's url.URL.ResolveReference() method. For example:
r, _ := requester.New(Get("http://test.com"), RelativeURL("red"))
fmt.Println(r.URL.String()) // http://test.com/red
Multiple arguments will be resolved in order:
r, _ := requester.New(Get("http://test.com"), RelativeURL("red", "blue"))
fmt.Println(r.URL.String()) // http://test.com/red/blue
func Use ¶
func Use(m ...Middleware) Option
Use appends middlware to Requester.Middleware. Middleware is invoked in the order added.
func WithDoer ¶
WithDoer replaces Requester.Doer. If nil, Requester will revert to using the http.DefaultClient.
func WithMarshaler ¶ added in v0.2.0
WithMarshaler sets Requester.WithMarshaler
func WithUnmarshaler ¶ added in v0.2.0
func WithUnmarshaler(m Unmarshaler) Option
WithUnmarshaler sets Requester.WithUnmarshaler
type OptionFunc ¶
OptionFunc adapts a function to the Option interface.
type Requester ¶
type Requester struct {
// Method defaults to "GET".
Method string
URL *url.URL
// Header supplies the request headers. If the Content-Type header
// is explicitly set here, it will override the Content-Type header
// supplied by the Marshaler.
Header http.Header
// advanced options, not typically used. If not sure, leave them
// blank.
// Most of these settings are set automatically by the http package.
// Setting them here will override the automatic values.
GetBody func() (io.ReadCloser, error)
ContentLength int64
TransferEncoding []string
Close bool
Host string
Trailer http.Header
// QueryParams are added to the request, in addition to any
// query params already encoded in the URL
QueryParams url.Values
// Body can be set to a string, []byte, io.Reader, or a struct.
// If set to a string, []byte, or io.Reader,
// the value will be used as the body of the request.
// If set to a struct, the Marshaler
// will be used to marshal the value into the request body.
Body interface{}
// Marshaler will be used to marshal the Body value into the body
// of requester. It is only used if Body is a struct value.
// Defaults to the DefaultMarshaler, which marshals to JSON.
//
// If no Content-Type header has been explicitly set in Requester.Header, the
// Marshaler will supply an appropriate one.
Marshaler Marshaler
// Doer holds the HTTP client for used to execute requester.
// Defaults to http.DefaultClient.
Doer Doer
// Middleware wraps the Doer. Middleware will be invoked in the order
// it is in this slice.
Middleware []Middleware
// Unmarshaler will be used by the Receive methods to unmarshal
// the response body. Defaults to DefaultUnmarshaler, which unmarshals
// multiple content types based on the Content-Type response header.
Unmarshaler Unmarshaler
}
Requester is an HTTP request builder and HTTP client.
Requester can be used to construct requests, send requests via a configurable HTTP client, and unmarshal the response. A Requester is configured by setting its members, which in most cases mirror the members of *http.Request. A Requester can also be configured by applying functional Options, which simply modify Requester's members.
Once configured, you can use Requester solely as a *http.Request factory, by calling Request() or RequestContext().
Requester can both construct and send requests (via a configurable Doer) with the Send() and SendContext() methods.
Finally, Requester can construct and send requests, and handle the responses with Receive() and ReceiveContext().
A Requester can be constructed as a literal:
r := requester.Requester{
URL: u,
Method: "POST",
Body: b,
}
...or via the New() constructor, which takes functional Options:
reqs, err := requester.New(requester.Post("http://test.com/red"), requester.Body(b))
Additional options can be applied with Apply():
err := reqs.Apply(requester.Accept("application/json"))
Requester can be cloned. The clone can then be further configured without affecting the parent:
reqs2 := reqs.Clone()
err := reqs2.Apply(Header("X-Frame","1"))
With() is equivalent to Clone() and Apply():
reqs2, err := reqs.With(requester.Header("X-Frame","1"))
The remaining methods of Requester are for creating HTTP requests, sending them, and handling the responses: Request(), Send(), and Receive().
req, err := reqs.Request() // create a requests resp, err := reqs.Send() // create and send a request var m Resource resp, body, err := reqs.Receive(&m) // create and send request, read and unmarshal response
Request(), Send(), and Receive() all accept a varargs of Options, which will be applied only to a single request, not to the Requester.
req, err := reqs.Request(
requester.Put("users/bob"),
requester.Body(bob),
)
RequestContext(), SendContext(), and ReceiveContext() variants accept a context, which is attached to the constructed request:
req, err := reqs.RequestContext(ctx)
func MustNew ¶
MustNew creates a new Requester, applying all options. If an error occurs applying options, this will panic.
func (*Requester) Clone ¶
Clone returns a deep copy of a Requester. Useful inheriting and adding settings from a parent Requester without modifying the parent. For example,
parent, _ := requester.New(Get("https://api.io/"))
foo := parent.Clone()
foo.Apply(Get("foo/"))
bar := parent.Clone()
bar.Apply(Post("bar/"))
foo and bar will both use the same client, but send requests to https://api.io/foo/ and https://api.io/bar/ respectively.
func (*Requester) Do ¶
Do implements Doer. Executes the request using the configured Doer and Middleware.
func (*Requester) Headers ¶
Headers returns the Header, initializing it if necessary. Never returns nil.
func (*Requester) Params ¶
Params returns the QueryParams, initializing them if necessary. Never returns nil.
func (*Requester) Receive ¶
func (r *Requester) Receive(into interface{}, opts ...Option) (resp *http.Response, body []byte, err error)
Receive creates a new HTTP request and returns the response. Success responses (2XX) are unmarshaled into successV. Any error creating the request, sending it, or decoding a 2XX response is returned.
If option arguments are passed, they are applied to this single request only.
If the into argument is an Option, then it's treated like an option and not unmarshaled into.
// these are all equivalent
r.Receive(Get())
r.Receive(nil, Get())
func (*Requester) ReceiveContext ¶
func (r *Requester) ReceiveContext(ctx context.Context, into interface{}, opts ...Option) (resp *http.Response, body []byte, err error)
ReceiveContext does the same as Receive, but requires a context.
func (*Requester) Request ¶
Request returns a new http.Request.
If Options are passed, they will only by applied to this single request.
If r.Body is a struct, it will be marshaled into the request body using r.Marshaler. The Marshaler will also set the Content-Type header, unless this header is already explicitly set in r.Header.
If r.Body is an io.Reader, string, or []byte, it is set as the request body directly, and no default Content-Type is set.
func (*Requester) RequestContext ¶
RequestContext does the same as Request, but requires a context. Use this to set a request timeout:
req, err := r.RequestContext(context.WithTimeout(context.Background(), 10 * time.Seconds))
func (*Requester) Send ¶
Send executes a request with the Doer. The response body is not closed: it is the caller's responsibility to close the response body. If the caller prefers the body as a byte slice, or prefers the body unmarshaled into a struct, see the Receive methods below.
Additional options arguments can be passed. They will be applied to this request only.
func (*Requester) SendContext ¶
SendContext does the same as Request, but requires a context.
type UnmarshalFunc ¶
UnmarshalFunc adapts a function to the Unmarshaler interface.
func (UnmarshalFunc) Apply ¶ added in v0.2.0
func (f UnmarshalFunc) Apply(r *Requester) error
Apply implements Option. UnmarshalFunc can be applied as a requester option, which install itself as the Unmarshaler.
type Unmarshaler ¶
Unmarshaler unmarshals a []byte response body into a value. It is provided the value of the Content-Type header from the response.
var DefaultUnmarshaler Unmarshaler = &MultiUnmarshaler{}
DefaultUnmarshaler is used by Requester if Requester.Unmarshaler is nil.
type XMLMarshaler ¶
type XMLMarshaler struct {
Indent bool
}
XMLMarshaler implements Marshaler and Unmarshaler. It marshals values to and from XML. If Indent is true, marshaled XML will be indented.
r := requester.Requester{
Marshaler: &XMLMarshaler{},
}
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package clientserver is a utility for writing HTTP tests.
|
Package clientserver is a utility for writing HTTP tests. |
|
Package httpclient is a set of utilities for creating and configuring instances of http.Client.
|
Package httpclient is a set of utilities for creating and configuring instances of http.Client. |
|
Package httptestutil contains utilities for use in HTTP tests, particular when using httptest.Server.
|
Package httptestutil contains utilities for use in HTTP tests, particular when using httptest.Server. |
