Documentation ¶
Overview ¶
Package r2 provides the ability to automatically iterate through Http requests.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "io" "log/slog" "net/http" "time" ) func main() { url := "http://example.com" ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithMaxRequestAttempts(3), r2.WithPeriod(time.Second), } for res, err := range r2.Get(ctx, url, opts...) { if err != nil { slog.WarnContext(ctx, "something happened.", slog.Any("error", err)) // Note: Even if continue is used, the iterator could be terminated. // Likewise, if break is used, the request could be re-executed in the background once more. continue } if res == nil { slog.WarnContext(ctx, "response is nil") continue } if res.StatusCode != http.StatusOK { slog.WarnContext(ctx, "unexpected status code.", slog.Int("expect", http.StatusOK), slog.Int("got", res.StatusCode)) continue } buf, err := io.ReadAll(res.Body) if err != nil { slog.ErrorContext(ctx, "failed to read response body.", slog.Any("error", err)) continue } slog.InfoContext(ctx, "response", slog.String("response", string(buf))) // There is no need to close the response body yourself as automatic closing is enabled by default. } }
Output:
Index ¶
- Constants
- func Delete(ctx context.Context, url string, body io.Reader, options ...internal.Option) iter.Seq2[*http.Response, error]
- func Do(ctx context.Context, url, method string, body io.Reader, ...) iter.Seq2[*http.Response, error]
- func Get(ctx context.Context, url string, options ...internal.Option) iter.Seq2[*http.Response, error]
- func Head(ctx context.Context, url string, options ...internal.Option) iter.Seq2[*http.Response, error]
- func Patch(ctx context.Context, url string, body io.Reader, options ...internal.Option) iter.Seq2[*http.Response, error]
- func Post(ctx context.Context, url string, body io.Reader, options ...internal.Option) iter.Seq2[*http.Response, error]
- func PostForm(ctx context.Context, url string, data url.Values, options ...internal.Option) iter.Seq2[*http.Response, error]
- func Put(ctx context.Context, url string, body io.Reader, options ...internal.Option) iter.Seq2[*http.Response, error]
- func WithAspect(aspect Aspect) internal.Option
- func WithAutoCloseResponseBody(autoCloseResponseBody bool) internal.Option
- func WithContentType(contentType string) internal.Option
- func WithHeader(header http.Header) internal.Option
- func WithHttpClient(client HttpClient) internal.Option
- func WithInterval(interval time.Duration) internal.Option
- func WithMaxRequestAttempts(maxRequestTimes int) internal.Option
- func WithPeriod(period time.Duration) internal.Option
- func WithTerminateIf(terminationCondition TerminationCondition) internal.Option
- type Aspect
- type HttpClient
- type Option
- type TerminationCondition
Examples ¶
Constants ¶
const ( ContentTypeApplicationJSON = "application/json" ContentTypeApplicationXML = "application/xml" ContentTypeApplicationFormURLEncoded = "application/x-www-form-urlencoded" ContentTypeMultipartFormData = "multipart/form-data" ContentTypeTextPlain = "text/plain" ContentTypeTextCSV = "text/csv" ContentTypeTextHTML = "text/html" ContentTypeTextCSS = "text/css" ContentTypeTextJavaScript = "text/javascript" ContentTypeApplicationJavaScript = "application/javascript" ContentTypeApplicationOctetStream = "application/octet-stream" ContentTypeApplicationMsgPack = "application/x-msgpack" ContentTypeApplicationPDF = "application/pdf" ContentTypeApplicationGzip = "application/gzip" ContentTypeApplicationZip = "application/zip" ContentTypeApplicationLZH = "application/x-lzh" ContentTypeApplicationTar = "application/x-tar" ContentTypeImageBMP = "image/bmp" ContentTypeImageGIF = "image/gif" ContentTypeImageJPEG = "image/jpeg" ContentTypeImagePNG = "image/png" ContentTypeImageSVG = "image/svg+xml" ContentTypeAudioWAV = "audio/wav" ContentTypeAudioMP3 = "audio/mp3" ContentTypeVideoMPEG = "video/mpeg" ContentTypeVideoMP4 = "video/mp4" )
ContentTypes
Variables ¶
This section is empty.
Functions ¶
func Delete ¶
func Delete(ctx context.Context, url string, body io.Reader, options ...internal.Option) iter.Seq2[*http.Response, error]
Delete sends HTTP DELETE requests until one of the following conditions is satisfied.
- request succeeded and no termination condition is specified by WithTerminateIf.
- condition that specified in WithTerminateIf is satisfied.
- response status code is a 4xx(client error) other than 429(Too Many Request).
- maximum number of requests specified in WithMaxRequestAttempts is reached.
- exceeds the deadline for the context.Context passed in the argument.
- when the for range loop is interrupted by break.
And during which time it continues to return http.Response and error.
Example ¶
package main import ( "bytes" "context" "github.com/miyamo2/r2" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithContentType(r2.ContentTypeApplicationJSON), r2.WithMaxRequestAttempts(3), r2.WithPeriod(time.Second), } body := bytes.NewBuffer([]byte(`{"foo": "bar"}`)) for res, err := range r2.Delete(ctx, "https://example.com", body, opts...) { // do something _, _ = res, err } }
Output:
func Do ¶ added in v0.3.0
func Do(ctx context.Context, url, method string, body io.Reader, options ...internal.Option) iter.Seq2[*http.Response, error]
Do send HTTP requests until one of the following conditions is satisfied.
- request succeeded and no termination condition is specified by WithTerminateIf.
- condition that specified in WithTerminateIf is satisfied.
- response status code is a 4xx(client error) other than 429(Too Many Request).
- maximum number of requests specified in WithMaxRequestAttempts is reached.
- exceeds the deadline for the context.Context passed in the argument.
- when the for range loop is interrupted by break.
And during which time it continues to return http.Response and error.
func Get ¶
func Get(ctx context.Context, url string, options ...internal.Option) iter.Seq2[*http.Response, error]
Get sends HTTP GET requests until one of the following conditions is satisfied.
- request succeeded and no termination condition is specified by WithTerminateIf.
- condition that specified in WithTerminateIf is satisfied.
- response status code is a 4xx(client error) other than 429(Too Many Request).
- maximum number of requests specified in WithMaxRequestAttempts is reached.
- exceeds the deadline for the context.Context passed in the argument.
- when the for range loop is interrupted by break.
And during which time it continues to return http.Response and error.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithMaxRequestAttempts(3), r2.WithPeriod(time.Second), } for res, err := range r2.Get(ctx, "https://example.com", opts...) { // do something _, _ = res, err } }
Output:
func Head ¶
func Head(ctx context.Context, url string, options ...internal.Option) iter.Seq2[*http.Response, error]
Head sends HTTP HEAD requests until one of the following conditions is satisfied.
- request succeeded and no termination condition is specified by WithTerminateIf.
- condition that specified in WithTerminateIf is satisfied.
- response status code is a 4xx(client error) other than 429(Too Many Request).
- maximum number of requests specified in WithMaxRequestAttempts is reached.
- exceeds the deadline for the context.Context passed in the argument.
- when the for range loop is interrupted by break.
And during which time it continues to return http.Response and error.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithMaxRequestAttempts(3), r2.WithPeriod(time.Second), } for res, err := range r2.Head(ctx, "https://example.com", opts...) { // do something _, _ = res, err } }
Output:
func Patch ¶
func Patch(ctx context.Context, url string, body io.Reader, options ...internal.Option) iter.Seq2[*http.Response, error]
Patch sends HTTP PATCH requests until one of the following conditions is satisfied.
- request succeeded and no termination condition is specified by WithTerminateIf.
- condition that specified in WithTerminateIf is satisfied.
- response status code is a 4xx(client error) other than 429(Too Many Request).
- maximum number of requests specified in WithMaxRequestAttempts is reached.
- exceeds the deadline for the context.Context passed in the argument.
- when the for range loop is interrupted by break.
And during which time it continues to return http.Response and error.
Example ¶
package main import ( "bytes" "context" "github.com/miyamo2/r2" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithContentType(r2.ContentTypeApplicationJSON), r2.WithMaxRequestAttempts(3), r2.WithPeriod(time.Second), } body := bytes.NewBuffer([]byte(`{"foo": "bar"}`)) for res, err := range r2.Patch(ctx, "https://example.com", body, opts...) { // do something _, _ = res, err } }
Output:
func Post ¶
func Post(ctx context.Context, url string, body io.Reader, options ...internal.Option) iter.Seq2[*http.Response, error]
Post sends HTTP POST requests until one of the following conditions is satisfied.
- request succeeded and no termination condition is specified by WithTerminateIf.
- condition that specified in WithTerminateIf is satisfied.
- response status code is a 4xx(client error) other than 429(Too Many Request).
- maximum number of requests specified in WithMaxRequestAttempts is reached.
- exceeds the deadline for the context.Context passed in the argument.
- when the for range loop is interrupted by break.
And during which time it continues to return http.Response and error.
Example ¶
package main import ( "bytes" "context" "github.com/miyamo2/r2" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithContentType(r2.ContentTypeApplicationJSON), r2.WithMaxRequestAttempts(3), r2.WithPeriod(time.Second), } body := bytes.NewBuffer([]byte(`{"foo": "bar"}`)) for res, err := range r2.Post(ctx, "https://example.com", body, opts...) { // do something _, _ = res, err } }
Output:
func PostForm ¶
func PostForm(ctx context.Context, url string, data url.Values, options ...internal.Option) iter.Seq2[*http.Response, error]
PostForm sends HTTP POST requests until one of the following conditions is satisfied.
- request succeeded and no termination condition is specified by WithTerminateIf.
- condition that specified in WithTerminateIf is satisfied.
- response status code is a 4xx(client error) other than 429(Too Many Request).
- maximum number of requests specified in WithMaxRequestAttempts is reached.
- exceeds the deadline for the context.Context passed in the argument.
- when the for range loop is interrupted by break.
And during which time it continues to return http.Response and error.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "net/url" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithContentType(r2.ContentTypeApplicationJSON), r2.WithMaxRequestAttempts(3), r2.WithPeriod(time.Second), } form := url.Values{"foo": []string{"bar"}} for res, err := range r2.PostForm(ctx, "https://example.com", form, opts...) { // do something _, _ = res, err } }
Output:
func Put ¶
func Put(ctx context.Context, url string, body io.Reader, options ...internal.Option) iter.Seq2[*http.Response, error]
Put sends HTTP PUT requests until one of the following conditions is satisfied.
- request succeeded and no termination condition is specified by WithTerminateIf.
- condition that specified in WithTerminateIf is satisfied.
- response status code is a 4xx(client error) other than 429(Too Many Request).
- maximum number of requests specified in WithMaxRequestAttempts is reached.
- exceeds the deadline for the context.Context passed in the argument.
- when the for range loop is interrupted by break.
And during which time it continues to return http.Response and error.
Example ¶
package main import ( "bytes" "context" "github.com/miyamo2/r2" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithContentType(r2.ContentTypeApplicationJSON), r2.WithMaxRequestAttempts(3), r2.WithPeriod(time.Second), } body := bytes.NewBuffer([]byte(`{"foo": "bar"}`)) for res, err := range r2.Put(ctx, "https://example.com", body, opts...) { // do something _, _ = res, err } }
Output:
func WithAspect ¶
WithAspect sets the behavior to the pre-request/post-request.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "net/http" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithAspect(func(req *http.Request, do func(req *http.Request) (*http.Response, error)) (*http.Response, error) { res, err := do(req) res.StatusCode += 1 return res, err }), } for res, err := range r2.Get(ctx, "https://example.com", opts...) { // do something _, _ = res, err } }
Output:
func WithAutoCloseResponseBody ¶
WithAutoCloseResponseBody sets whether the response body is automatically closed. By default, this setting is enabled.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithAutoCloseResponseBody(true), } for res, err := range r2.Get(ctx, "https://example.com", opts...) { // do something _, _ = res, err } }
Output:
func WithContentType ¶
WithContentType sets the content type for the request header.
func WithHeader ¶
WithHeader sets custom http headers for the request.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "net/http" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithHeader(http.Header{"X-My-Header": []string{"my-value"}}), } for res, err := range r2.Get(ctx, "https://example.com", opts...) { // do something _, _ = res, err } }
Output:
func WithHttpClient ¶
func WithHttpClient(client HttpClient) internal.Option
WithHttpClient sets a custom HTTP client for the request.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "net/http" "time" ) var myHttpClient *http.Client func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithHttpClient(myHttpClient), } for res, err := range r2.Get(ctx, "https://example.com", opts...) { // do something _, _ = res, err } }
Output:
func WithInterval ¶
WithInterval sets the interval between next request. By default, the interval is calculated by the exponential backoff and jitter. If response status code is 429(Too Many Request), the interval conforms to 'Retry-After' header.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithInterval(time.Second), } for res, err := range r2.Get(ctx, "https://example.com", opts...) { // do something _, _ = res, err } }
Output:
func WithMaxRequestAttempts ¶ added in v0.2.0
WithMaxRequestAttempts sets the maximum number of requests. If less than or equal to 0 is specified, maximum number of requests does not apply.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithMaxRequestAttempts(3), } for res, err := range r2.Get(ctx, "https://example.com", opts...) { // do something _, _ = res, err } }
Output:
func WithPeriod ¶
WithPeriod sets the timeout period for the per request. If less than or equal to 0 is specified, the timeout period does not apply.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithPeriod(time.Second), } for res, err := range r2.Get(ctx, "https://example.com", opts...) { // do something _, _ = res, err } }
Output:
func WithTerminateIf ¶ added in v0.2.0
func WithTerminateIf(terminationCondition TerminationCondition) internal.Option
WithTerminateIf sets the termination condition of the iterator that references the response.
Example ¶
package main import ( "context" "github.com/miyamo2/r2" "net/http" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() opts := []r2.Option{ r2.WithTerminateIf(func(res *http.Response, _ error) bool { myHeader := res.Header.Get("X-My-Header") return len(myHeader) > 0 }), } for res, err := range r2.Get(ctx, "https://example.com", opts...) { // do something _, _ = res, err } }
Output:
Types ¶
type HttpClient ¶
type HttpClient = internal.HttpClient
HttpClient specifies the interface for the custom HTTP client.
type TerminationCondition ¶
type TerminationCondition = internal.TerminationCondition
TerminationCondition specifies the termination condition of the iterator that references the response.