Skip to content

Commit

Permalink
New Extend API for intuitively extending URL path
Browse files Browse the repository at this point in the history
Currently to extend current rawURL we have to use Path() API which is
okay but comes with some nuances:
- Current rawURL must end in `/` to be extensible.
- The new path should end in `/` to be further extensible.
Plus it is not easy to create an intuitive looking api like this where
each step appends a new path:

// Get one student
client.Students().Student("id").Get() // GET http://server/students/id
// Update one student
client.Students().Student("id").Update(...) // POST http://server/students/id
// Get all students
client.Students().Get() // GET http://server/students

If we use Path() API then `Students()` method cannot simply append
`/students` to rawURL because we want the new URL to be further
extendible by `Student("id")` method. On the other hand if we try to add
`students/ ` in Students() then first two calls will work but now last
call wont work because the rawURL for that call would be:
`http://server/students/`.

The new Extend API solves this problem and makes it very intitive and no
brainer for appending/extending URL paths.
  • Loading branch information
rsjethani committed Jul 11, 2023
1 parent b285c20 commit 7a1ff5d
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 18 deletions.
10 changes: 9 additions & 1 deletion sling.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,15 @@ func (s *Sling) Path(path string) *Sling {
pathURL, pathErr := url.Parse(path)
if baseErr == nil && pathErr == nil {
s.rawURL = baseURL.ResolveReference(pathURL).String()
return s
}
return s
}

// Extend simply extends the rawURL by appending path to it using [url.JoinPath].
// If parsing error occurs, the rawURL is left unmodified.
func (s *Sling) Extend(path string) *Sling {
if u, err := url.JoinPath(s.rawURL, path); err == nil {
s.rawURL = u
}
return s
}
Expand Down
55 changes: 38 additions & 17 deletions sling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,27 @@ func TestPathSetter(t *testing.T) {
}
}

func TestExtend(t *testing.T) {
cases := []struct {
rawURL string
extensions []string
expectedRawURL string
}{
{"http://a.io", []string{"foo", "bar"}, "http://a.io/foo/bar"},
{"http://a.io/", []string{"foo", "bar"}, "http://a.io/foo/bar"},
{"http://a.io/", []string{"/foo", "./bar"}, "http://a.io/foo/bar"},
}
for _, c := range cases {
sl := New().Base(c.rawURL)
for _, e := range c.extensions {
sl.Extend(e)
}
if sl.rawURL != c.expectedRawURL {
t.Errorf("expected %s, got %s", c.expectedRawURL, sl.rawURL)
}
}
}

func TestMethodSetters(t *testing.T) {
cases := []struct {
sling *Sling
Expand Down Expand Up @@ -953,23 +974,23 @@ func TestReceive_errorCreatingRequest(t *testing.T) {
}

func TestReceive_context(t *testing.T) {
client, mux, server := testServer()
defer server.Close()
mux.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
})

ctx, fn := context.WithCancel(context.Background())
defer fn()

endpoint := New().Client(client).Get("http://example.com/foo")
resp, err := endpoint.New().ReceiveWithContext(ctx, nil, nil)
if err != nil {
t.Errorf("expected nil, got %v", err)
}

if resp.Request.Context() != ctx {
t.Error("request.Context() is not same as context passed during receive operation")
}
client, mux, server := testServer()
defer server.Close()
mux.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
})

ctx, fn := context.WithCancel(context.Background())
defer fn()

endpoint := New().Client(client).Get("http://example.com/foo")
resp, err := endpoint.New().ReceiveWithContext(ctx, nil, nil)
if err != nil {
t.Errorf("expected nil, got %v", err)
}

if resp.Request.Context() != ctx {
t.Error("request.Context() is not same as context passed during receive operation")
}
}

func TestReuseTcpConnections(t *testing.T) {
Expand Down

0 comments on commit 7a1ff5d

Please sign in to comment.