Skip to content

Commit ab4c5f9

Browse files
committed
chore: implement generic function for codersdk request methods
Currently we copy + paste and tweak. Makes sense to DRY and reuse a standard request function.
1 parent f1cb3a5 commit ab4c5f9

File tree

2 files changed

+71
-78
lines changed

2 files changed

+71
-78
lines changed

codersdk/organizations.go

+33-78
Original file line numberDiff line numberDiff line change
@@ -210,33 +210,19 @@ type CreateWorkspaceRequest struct {
210210
}
211211

212212
func (c *Client) OrganizationByName(ctx context.Context, name string) (Organization, error) {
213-
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s", name), nil)
214-
if err != nil {
215-
return Organization{}, xerrors.Errorf("execute request: %w", err)
216-
}
217-
defer res.Body.Close()
218-
219-
if res.StatusCode != http.StatusOK {
220-
return Organization{}, ReadBodyAsError(res)
221-
}
222-
223-
var organization Organization
224-
return organization, json.NewDecoder(res.Body).Decode(&organization)
213+
return makeSDKRequest[Organization](ctx, c, sdkRequestArgs{
214+
Method: http.MethodGet,
215+
URL: fmt.Sprintf("/api/v2/organizations/%s", name),
216+
ExpectCode: http.StatusOK,
217+
})
225218
}
226219

227220
func (c *Client) Organizations(ctx context.Context) ([]Organization, error) {
228-
res, err := c.Request(ctx, http.MethodGet, "/api/v2/organizations", nil)
229-
if err != nil {
230-
return []Organization{}, xerrors.Errorf("execute request: %w", err)
231-
}
232-
defer res.Body.Close()
233-
234-
if res.StatusCode != http.StatusOK {
235-
return []Organization{}, ReadBodyAsError(res)
236-
}
237-
238-
var organizations []Organization
239-
return organizations, json.NewDecoder(res.Body).Decode(&organizations)
221+
return makeSDKRequest[[]Organization](ctx, c, sdkRequestArgs{
222+
Method: http.MethodGet,
223+
URL: "/api/v2/organizations",
224+
ExpectCode: http.StatusOK,
225+
})
240226
}
241227

242228
func (c *Client) Organization(ctx context.Context, id uuid.UUID) (Organization, error) {
@@ -264,34 +250,23 @@ func (c *Client) CreateOrganization(ctx context.Context, req CreateOrganizationR
264250
// UpdateOrganization will update information about the corresponding organization, based on
265251
// the UUID/name provided as `orgID`.
266252
func (c *Client) UpdateOrganization(ctx context.Context, orgID string, req UpdateOrganizationRequest) (Organization, error) {
267-
res, err := c.Request(ctx, http.MethodPatch, fmt.Sprintf("/api/v2/organizations/%s", orgID), req)
268-
if err != nil {
269-
return Organization{}, xerrors.Errorf("execute request: %w", err)
270-
}
271-
defer res.Body.Close()
272-
273-
if res.StatusCode != http.StatusOK {
274-
return Organization{}, ReadBodyAsError(res)
275-
}
276-
277-
var organization Organization
278-
return organization, json.NewDecoder(res.Body).Decode(&organization)
253+
return makeSDKRequest[Organization](ctx, c, sdkRequestArgs{
254+
Method: http.MethodPatch,
255+
URL: fmt.Sprintf("/api/v2/organizations/%s", orgID),
256+
Body: req,
257+
ExpectCode: http.StatusOK,
258+
})
279259
}
280260

281261
// DeleteOrganization will remove the corresponding organization from the deployment, based on
282262
// the UUID/name provided as `orgID`.
283263
func (c *Client) DeleteOrganization(ctx context.Context, orgID string) error {
284-
res, err := c.Request(ctx, http.MethodDelete, fmt.Sprintf("/api/v2/organizations/%s", orgID), nil)
285-
if err != nil {
286-
return xerrors.Errorf("execute request: %w", err)
287-
}
288-
defer res.Body.Close()
289-
290-
if res.StatusCode != http.StatusOK {
291-
return ReadBodyAsError(res)
292-
}
293-
294-
return nil
264+
_, err := makeSDKRequest[noResponse](ctx, c, sdkRequestArgs{
265+
Method: http.MethodDelete,
266+
URL: fmt.Sprintf("/api/v2/organizations/%s", orgID),
267+
ExpectCode: http.StatusOK,
268+
})
269+
return err
295270
}
296271

297272
// ProvisionerDaemons returns provisioner daemons available.
@@ -445,44 +420,24 @@ func (f TemplateFilter) asRequestOption() RequestOption {
445420

446421
// Templates lists all viewable templates
447422
func (c *Client) Templates(ctx context.Context, filter TemplateFilter) ([]Template, error) {
448-
res, err := c.Request(ctx, http.MethodGet,
449-
"/api/v2/templates",
450-
nil,
451-
filter.asRequestOption(),
452-
)
453-
if err != nil {
454-
return nil, xerrors.Errorf("execute request: %w", err)
455-
}
456-
defer res.Body.Close()
457-
458-
if res.StatusCode != http.StatusOK {
459-
return nil, ReadBodyAsError(res)
460-
}
461-
462-
var templates []Template
463-
return templates, json.NewDecoder(res.Body).Decode(&templates)
423+
return makeSDKRequest[[]Template](ctx, c, sdkRequestArgs{
424+
Method: http.MethodGet,
425+
URL: "/api/v2/templates",
426+
ExpectCode: http.StatusOK,
427+
ReqOpts: []RequestOption{filter.asRequestOption()},
428+
})
464429
}
465430

466431
// TemplateByName finds a template inside the organization provided with a case-insensitive name.
467432
func (c *Client) TemplateByName(ctx context.Context, organizationID uuid.UUID, name string) (Template, error) {
468433
if name == "" {
469434
return Template{}, xerrors.Errorf("template name cannot be empty")
470435
}
471-
res, err := c.Request(ctx, http.MethodGet,
472-
fmt.Sprintf("/api/v2/organizations/%s/templates/%s", organizationID.String(), name),
473-
nil,
474-
)
475-
if err != nil {
476-
return Template{}, xerrors.Errorf("execute request: %w", err)
477-
}
478-
defer res.Body.Close()
479-
480-
if res.StatusCode != http.StatusOK {
481-
return Template{}, ReadBodyAsError(res)
482-
}
483-
484-
var template Template
485-
return template, json.NewDecoder(res.Body).Decode(&template)
436+
return makeSDKRequest[Template](ctx, c, sdkRequestArgs{
437+
Method: http.MethodGet,
438+
URL: fmt.Sprintf("/api/v2/organizations/%s/templates/%s", organizationID.String(), name),
439+
ExpectCode: http.StatusOK,
440+
})
486441
}
487442

488443
// CreateWorkspace creates a new workspace for the template specified.

codersdk/request.go

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package codersdk
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
)
7+
8+
type sdkRequestArgs struct {
9+
Method string
10+
URL string
11+
Body any
12+
ReqOpts []RequestOption
13+
ExpectCode int
14+
}
15+
16+
type noResponse struct{}
17+
18+
func makeSDKRequest[T any](ctx context.Context, cli *Client, req sdkRequestArgs) (T, error) {
19+
var empty T
20+
res, err := cli.Request(ctx, req.Method, req.URL, req.Body, req.ReqOpts...)
21+
if err != nil {
22+
return empty, err
23+
}
24+
defer res.Body.Close()
25+
26+
if res.StatusCode != req.ExpectCode {
27+
return empty, ReadBodyAsError(res)
28+
}
29+
30+
switch (any)(empty).(type) {
31+
case noResponse:
32+
// noResponse means the caller does not care about the response body
33+
return empty, nil
34+
default:
35+
}
36+
var result T
37+
return result, json.NewDecoder(res.Body).Decode(&result)
38+
}

0 commit comments

Comments
 (0)