Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
run: |
echo "## Lines of code" >> $GITHUB_STEP_SUMMARY

go install github.com/boyter/scc/v3@latest
go install github.com/boyter/scc/v3@v3.6.0
scc --format html-table . | tee -a $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
run: |
echo "## Lines of code" >> $GITHUB_STEP_SUMMARY

go install github.com/boyter/scc/v3@latest
go install github.com/boyter/scc/v3@v3.6.0
scc --format html-table . | tee -a $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# httpretrier

[![Go Reference](https://pkg.go.dev/badge/github.com/p2p-b2b/httpretrier.svg)](https://pkg.go.dev/github.com/p2p-b2b/httpretrier)
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/p2p-b2b/httpretrier?style=plastic)
[![Go Reference](https://pkg.go.dev/badge/github.com/slashdevops/httpretrier.svg)](https://pkg.go.dev/github.com/slashdevops/httpretrier)
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/slashdevops/httpretrier?style=plastic)

`httpretrier` is a Go library that provides a **transparent** drop-in replacement for `http.Client` with automatic retry logic. It preserves all existing request headers (including authentication) while handling transient server errors (5xx) or network issues by retrying requests based on configurable strategies.

Expand All @@ -23,13 +23,13 @@
## Installation

```bash
go get github.com/p2p-b2b/httpretrier@latest
go get github.com/slashdevops/httpretrier@latest
```

## Update

```bash
go get -u github.com/p2p-b2b/httpretrier@latest
go get -u github.com/slashdevops/httpretrier@latest
```

## Usage
Expand Down Expand Up @@ -66,7 +66,7 @@ import (
"sync/atomic"
"time"

"github.com/p2p-b2b/httpretrier"
"github.com/slashdevops/httpretrier"
)

func main() {
Expand Down Expand Up @@ -124,7 +124,7 @@ import (
"net/http"
"time"

"github.com/p2p-b2b/httpretrier"
"github.com/slashdevops/httpretrier"
)

func main() {
Expand Down Expand Up @@ -172,7 +172,7 @@ import (
"net/http/httptest"
"time"

"github.com/p2p-b2b/httpretrier"
"github.com/slashdevops/httpretrier"
)

func main() {
Expand Down
24 changes: 8 additions & 16 deletions example_httpretrier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import (
"io"
"net/http"
"net/http/httptest"
"net/url"
"sync/atomic"
"time"

"github.com/p2p-b2b/httpretrier"
"github.com/slashdevops/httpretrier"
)

// Example demonstrates using exponential backoff.
Expand Down Expand Up @@ -42,7 +41,7 @@ func Example() {
fmt.Printf("Client: Request failed: %v\n", err)
return
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()

body, _ := io.ReadAll(resp.Body)
fmt.Printf("Client: Received response: Status=%s, Body='%s'\n", resp.Status, string(body))
Expand Down Expand Up @@ -82,7 +81,7 @@ func ExampleNewClient_withExistingAuth() {
} else {
fmt.Println("200 OK")
w.WriteHeader(http.StatusOK)
w.Write([]byte("Authenticated and retried successfully"))
_, _ = w.Write([]byte("Authenticated and retried successfully"))
}
}))
defer server.Close()
Expand All @@ -100,7 +99,7 @@ func ExampleNewClient_withExistingAuth() {
fmt.Printf("Client: Request failed: %v\n", err)
return
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()

body, _ := io.ReadAll(resp.Body)
fmt.Printf("Client: Success! Status=%s, Body='%s'\n", resp.Status, string(body))
Expand All @@ -126,7 +125,7 @@ func ExampleNewClientBuilder_transparent() {
fmt.Printf("Server: Received custom header: %s\n", customValue)
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("Custom headers preserved!"))
_, _ = w.Write([]byte("Custom headers preserved!"))
}))
defer server.Close()

Expand All @@ -148,7 +147,7 @@ func ExampleNewClientBuilder_transparent() {
fmt.Printf("Client: Request failed: %v\n", err)
return
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()

body, _ := io.ReadAll(resp.Body)
fmt.Printf("Client: Response: %s\n", string(body))
Expand All @@ -173,7 +172,7 @@ func ExampleNewClient_withCustomTransport() {
w.WriteHeader(http.StatusInternalServerError)
} else {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Custom transport with retries works!"))
_, _ = w.Write([]byte("Custom transport with retries works!"))
}
}))
defer server.Close()
Expand All @@ -200,7 +199,7 @@ func ExampleNewClient_withCustomTransport() {
fmt.Printf("Client: Request failed: %v\n", err)
return
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()

body, _ := io.ReadAll(resp.Body)
fmt.Printf("Client: Response: %s\n", string(body))
Expand All @@ -216,10 +215,3 @@ func ExampleNewClient_withCustomTransport() {
}

// Helper function to parse URL (avoiding error handling in example)
func mustParseURL(rawURL string) *url.URL {
u, err := url.Parse(rawURL)
if err != nil {
panic(err)
}
return u
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/p2p-b2b/httpretrier
module github.com/slashdevops/httpretrier

go 1.25.1
go 1.26.4
10 changes: 5 additions & 5 deletions httpretrier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func TestRetryTransport_SuccessOnFirstAttempt(t *testing.T) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusOK {
t.Errorf("Expected status code %d, got %d", http.StatusOK, resp.StatusCode)
Expand Down Expand Up @@ -167,7 +167,7 @@ func TestRetryTransport_SuccessAfterRetries(t *testing.T) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusOK {
t.Errorf("Expected status code %d, got %d", http.StatusOK, resp.StatusCode)
Expand Down Expand Up @@ -318,7 +318,7 @@ func TestRetryTransport_RequestBodyCloning(t *testing.T) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusOK {
t.Errorf("Expected status OK, got %d", resp.StatusCode)
Expand Down Expand Up @@ -388,7 +388,7 @@ func TestRetryTransport_NilRetryStrategyUsesDefault(t *testing.T) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()

if resp.StatusCode != http.StatusOK {
t.Errorf("Expected status OK, got %d", resp.StatusCode)
Expand Down Expand Up @@ -424,7 +424,7 @@ func TestRetryTransport_NonRetryableError(t *testing.T) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()

// Should return immediately with the 400 status, no retries
if resp.StatusCode != http.StatusBadRequest {
Expand Down