Skip to content

Commit 946c00e

Browse files
committed
Add public MakeRequest method to client.
Most of the time, sdk users will interact with the api using generated client methods. However, in some cases it may be useful to interact with the api more directly, analogous to `oxide api` in the cli. For example, users may want to invoke an api method that isn't yet supported in the sdk. This patch adds a new public method called MakeRequest that allows users to send custom requests to the api.
1 parent b94b9b5 commit 946c00e

2 files changed

Lines changed: 83 additions & 0 deletions

File tree

oxide/lib.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,22 @@ func (c *Client) buildRequest(ctx context.Context, body io.Reader, method, uri s
301301

302302
return req, nil
303303
}
304+
305+
type Request struct {
306+
Method string
307+
Path string
308+
Body io.Reader
309+
Params map[string]string
310+
Query map[string]string
311+
}
312+
313+
// MakeRequest takes a `Request` that defines the desired API request, builds
314+
// the URI using the configured API host, and sends the request to the API.
315+
func (c *Client) MakeRequest(ctx context.Context, req Request) (*http.Response, error) {
316+
uri := resolveRelative(c.host, req.Path)
317+
httpReq, err := c.buildRequest(ctx, req.Body, req.Method, uri, req.Params, req.Query)
318+
if err != nil {
319+
return nil, fmt.Errorf("building request failed: %v", err)
320+
}
321+
return c.client.Do(httpReq)
322+
}

oxide/lib_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"encoding/json"
1111
"io"
1212
"net/http"
13+
"net/http/httptest"
1314
"net/url"
1415
"os"
1516
"path/filepath"
@@ -470,3 +471,66 @@ user = "other-user"
470471

471472
return tmpDir
472473
}
474+
475+
func Test_MakeRequest(t *testing.T) {
476+
tests := []struct {
477+
name string
478+
request Request
479+
expectedQuery string
480+
}{
481+
{
482+
name: "request without optional fields",
483+
request: Request{
484+
Method: http.MethodGet,
485+
Path: "/v1/projects",
486+
},
487+
expectedQuery: "",
488+
},
489+
{
490+
name: "request with all fields",
491+
request: Request{
492+
Method: http.MethodPost,
493+
Path: "/v1/projects",
494+
Body: strings.NewReader(`{"name":"my-project"}`),
495+
Params: map[string]string{
496+
"project": "my-project",
497+
},
498+
Query: map[string]string{
499+
"project": "my-project",
500+
},
501+
},
502+
expectedQuery: "project=my-project",
503+
},
504+
}
505+
506+
for _, tc := range tests {
507+
t.Run(tc.name, func(t *testing.T) {
508+
var capturedRequest *http.Request
509+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
510+
capturedRequest = r
511+
w.WriteHeader(http.StatusOK)
512+
_, err := w.Write([]byte(`{"status":"ok"}`))
513+
require.NoError(t, err)
514+
}))
515+
defer server.Close()
516+
517+
client, err := NewClient(&Config{
518+
Host: server.URL,
519+
Token: "test-token",
520+
})
521+
require.NoError(t, err)
522+
523+
resp, err := client.MakeRequest(context.Background(), tc.request)
524+
require.NoError(t, err)
525+
require.NotNil(t, resp)
526+
defer resp.Body.Close()
527+
528+
require.NotNil(t, capturedRequest)
529+
assert.Equal(t, tc.request.Method, capturedRequest.Method)
530+
assert.Equal(t, tc.request.Path, capturedRequest.URL.Path)
531+
assert.Equal(t, tc.expectedQuery, capturedRequest.URL.RawQuery)
532+
533+
assert.Equal(t, http.StatusOK, resp.StatusCode)
534+
})
535+
}
536+
}

0 commit comments

Comments
 (0)