From 31e6b9f7f7bc1703fff7b5b1341f527b11ae2333 Mon Sep 17 00:00:00 2001 From: Dennis Gloss Date: Tue, 17 Dec 2024 00:23:11 +0100 Subject: [PATCH 1/3] Add timeout to config --- fetch.go | 11 ++++++++++- fetch_it_test.go | 27 +++++++++++++++++++++++++++ fetch_test.go | 14 +++++++------- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/fetch.go b/fetch.go index 6b8466a..3e0b706 100644 --- a/fetch.go +++ b/fetch.go @@ -10,6 +10,7 @@ import ( "net/http" "reflect" "strings" + "time" ) var httpClient = &http.Client{} @@ -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 @@ -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" diff --git a/fetch_it_test.go b/fetch_it_test.go index 6d16fb6..33ccc35 100644 --- a/fetch_it_test.go +++ b/fetch_it_test.go @@ -2,6 +2,7 @@ package fetch import ( "context" + "errors" "net/http" "testing" "time" @@ -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 +} diff --git a/fetch_test.go b/fetch_test.go index ce292dc..b4f1d66 100644 --- a/fetch_test.go +++ b/fetch_test.go @@ -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) @@ -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) @@ -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) @@ -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) @@ -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 } @@ -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) @@ -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) From 7da61929e5587af157f3a659daa5a9c0301fc6b5 Mon Sep 17 00:00:00 2001 From: Dennis Gloss Date: Tue, 17 Dec 2024 00:30:44 +0100 Subject: [PATCH 2/3] update readme --- README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d24b91d..314850c 100644 --- a/README.md +++ b/README.md @@ -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 From 642e52a8246e71994252eb8a3fb28c90a8c785a5 Mon Sep 17 00:00:00 2001 From: Dennis Gloss Date: Tue, 17 Dec 2024 00:33:08 +0100 Subject: [PATCH 3/3] update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 314850c..3b82cab 100644 --- a/README.md +++ b/README.md @@ -283,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