From cbdaa0d569fd893e825c2d5f9151418926ea4f5a Mon Sep 17 00:00:00 2001 From: Ilya Yaroslavtsev Date: Fri, 25 Apr 2025 19:30:13 +0500 Subject: [PATCH] Add methods accepting context.Context In many cases, a request should be attached to a context. This change allows for providing a parent context when a request is constructed --- sling.go | 25 +++++++++++++++++++++++++ sling_test.go | 17 +++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/sling.go b/sling.go index 5492ef2..2293497 100644 --- a/sling.go +++ b/sling.go @@ -1,6 +1,7 @@ package sling import ( + "context" "encoding/base64" "io" "net/http" @@ -302,6 +303,16 @@ func (s *Sling) Request() (*http.Request, error) { return req, err } +// RequestCtx returns a new http.Request created with the Sling properties and the given context. +func (s *Sling) RequestCtx(ctx context.Context) (*http.Request, error) { + req, err := s.Request() + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + return req, nil +} + // addQueryStructs parses url tagged query structs using go-querystring to // encode them to url.Values and format them onto the url.RawQuery. Any // query parsing or encoding errors are returned. @@ -356,6 +367,11 @@ func (s *Sling) ReceiveSuccess(successV interface{}) (*http.Response, error) { return s.Receive(successV, nil) } +// ReceiveSuccessCtx is like ReceiveSuccess but add context.Context to the request. +func (s *Sling) ReceiveSuccessCtx(ctx context.Context, successV interface{}) (*http.Response, error) { + return s.ReceiveCtx(ctx, successV, nil) +} + // Receive creates a new HTTP request and returns the response. Success // responses (2XX) are JSON decoded into the value pointed to by successV and // other responses are JSON decoded into the value pointed to by failureV. @@ -371,6 +387,15 @@ func (s *Sling) Receive(successV, failureV interface{}) (*http.Response, error) return s.Do(req, successV, failureV) } +// ReceiveCtx is like Receive but add context.Context to the request. +func (s *Sling) ReceiveCtx(ctx context.Context, successV, failureV interface{}) (*http.Response, error) { + req, err := s.RequestCtx(ctx) + if err != nil { + return nil, err + } + return s.Do(req, successV, failureV) +} + // Do sends an HTTP request and returns the response. Success responses (2XX) // are JSON decoded into the value pointed to by successV and other responses // are JSON decoded into the value pointed to by failureV. diff --git a/sling_test.go b/sling_test.go index 370c920..b1e49a5 100644 --- a/sling_test.go +++ b/sling_test.go @@ -580,6 +580,23 @@ func TestRequest_headers(t *testing.T) { } } +func TestRequestCtx_contextIsSet(t *testing.T) { + // Create a simple sling with a base URL + sling := New().Base("http://a.io/") + + ctx := context.Background() + req, err := sling.RequestCtx(ctx) + + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Check that the request has the same context we provided + if req.Context() != ctx { + t.Error("expected request context to be the same as provided context") + } +} + func TestAddQueryStructs(t *testing.T) { cases := []struct { rawurl string