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
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,19 @@ if err != nil {
}
```
### Make request with Go Context
Request with 5 seconds timeout:
Request Context lives in `fetch.Config`
```go
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := fetch.Get[string]("https://petstore.swagger.io/v2/pet/1", fetch.Config{Ctx: ctx})
if err != nil {
panic(err)
func myFuncWithContext(ctx context.Context) {
...
res, err := fetch.Get[string]("https://petstore.swagger.io/v2/pet/1", fetch.Config{Ctx: ctx})
...
}
```
Request with 5 seconds timeout:
```go
fetch.Get[string]("https://petstore.swagger.io/v2/pet/1", fetch.Config{Timeout: 5*time.Second})
```


### Request with headers
```go
Expand Down Expand Up @@ -279,6 +283,8 @@ Each HTTP method has the configuration option.
type Config struct {
// Defaults to context.Background()
Ctx context.Context
// Sets Ctx with the specified timeout. If Ctx is specified Timeout is ignored.
Timeout time.Duration
// Defaults to GET
Method string
Body string
Expand Down
11 changes: 10 additions & 1 deletion fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net/http"
"reflect"
"strings"
"time"
)

var httpClient = &http.Client{}
Expand All @@ -18,6 +19,8 @@ var baseURL = ""
type Config struct {
// Defaults to context.Background()
Ctx context.Context
// Sets Ctx with the specified timeout. If Ctx is specified Timeout is ignored.
Timeout time.Duration
// Defaults to GET
Method string
Body string
Expand Down Expand Up @@ -104,7 +107,13 @@ func Do[T any](url string, config ...Config) (T, error) {
}

if cfg.Ctx == nil {
cfg.Ctx = context.Background()
if cfg.Timeout > 0 {
var cancel context.CancelFunc
cfg.Ctx, cancel = context.WithTimeout(context.Background(), cfg.Timeout)
defer cancel()
} else {
cfg.Ctx = context.Background()
}
}
if cfg.Method == "" {
cfg.Method = "GET"
Expand Down
27 changes: 27 additions & 0 deletions fetch_it_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fetch

import (
"context"
"errors"
"net/http"
"testing"
"time"
Expand Down Expand Up @@ -96,3 +97,29 @@ func TestIssue1(t *testing.T) {
t.Errorf("wrong response")
}
}

func TestTimeout(t *testing.T) {
mock = false
defer func() { mock = true }()
mux := http.NewServeMux()
mux.HandleFunc("/delay", func(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Minute)
w.WriteHeader(200)
})
server := &http.Server{Addr: ":7349", Handler: mux}
go server.ListenAndServe()
serverCtx, cancel := context.WithCancel(context.Background())
defer server.Shutdown(serverCtx)
time.Sleep(time.Millisecond)

ctx, _ := context.WithTimeout(context.Background(), 10*time.Millisecond)
_, err := Post[string]("http://localhost:7349/delay", nil, Config{Ctx: ctx})
if err == nil || !errors.Is(err, context.DeadlineExceeded) {
t.Fatalf("expected context deadealine, got=%v", err)
}
_, err = Post[string]("http://localhost:7349/delay", nil, Config{Timeout: 10 * time.Millisecond})
if err == nil || !errors.Is(err, context.DeadlineExceeded) {
t.Fatalf("expected context deadealine, got=%v", err)
}
cancel() // kill sleeping http handlers
}
14 changes: 7 additions & 7 deletions fetch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func TestMain(m *testing.M) {
os.Exit(code)
}

func TestRequestString(t *testing.T) {
func TestDoString(t *testing.T) {
res, err := Do[string]("my.ip")
if err != nil {
t.Fatal(err)
Expand All @@ -22,7 +22,7 @@ func TestRequestString(t *testing.T) {
}
}

func TestRequestBytes(t *testing.T) {
func TestDoBytes(t *testing.T) {
res, err := Do[[]byte]("array.int")
if err != nil {
t.Fatal(err)
Expand All @@ -33,7 +33,7 @@ func TestRequestBytes(t *testing.T) {
}
}

func TestRequestArray(t *testing.T) {
func TestDoArray(t *testing.T) {
res, err := Do[[]int]("array.int")
if err != nil {
t.Fatal(err)
Expand All @@ -43,7 +43,7 @@ func TestRequestArray(t *testing.T) {
}
}

func TestRequestAny(t *testing.T) {
func TestDoAny(t *testing.T) {
res, err := Do[any]("key.value")
if err != nil {
t.Fatal(err)
Expand All @@ -69,7 +69,7 @@ func TestRequestAny(t *testing.T) {
}
}

func TestRequest_ResponseT(t *testing.T) {
func TestDo_ResponseT(t *testing.T) {
type TestStruct struct {
Key string
}
Expand Down Expand Up @@ -98,7 +98,7 @@ func TestRequest_ResponseT(t *testing.T) {
}
}

func TestRequest_ResponseEmpty(t *testing.T) {
func TestDo_ResponseEmpty(t *testing.T) {
res, err := Do[Response[Empty]]("key.value")
if err != nil {
t.Error(err)
Expand All @@ -116,7 +116,7 @@ func TestRequest_ResponseEmpty(t *testing.T) {
}
}

func TestRequest_Error(t *testing.T) {
func TestDo_Error(t *testing.T) {
_, err := Do[string]("400.error")
if err == nil {
t.Fatal(err)
Expand Down
Loading