Skip to content

Commit 521047c

Browse files
committed
v2: return zero values on error
In Go, the default assumption is that if a func returns (T, error) and its error is non-nil, the T value is invalid unless otherwise documented. (io.Reader is the common example of a documented case where both results can be valid) On the flip side, the best practice for funcs returning (T, error) is to only set one or the other non-nil, lest callers accidentally depend on T always being non-nil and ossifying the implementation, making it unable to be refactored later. Updates #cleanup Signed-off-by: Brad Fitzpatrick <[email protected]>
1 parent b312198 commit 521047c

File tree

11 files changed

+38
-35
lines changed

11 files changed

+38
-35
lines changed

v2/client.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,27 @@ func (c *Client) buildRequest(ctx context.Context, method string, uri *url.URL,
285285
return req, nil
286286
}
287287

288-
func (c *Client) do(req *http.Request, out interface{}) error {
288+
// doer is a resource type (such as *ContactsResource) with a do method that
289+
// sends an HTTP request and decodes its body into out.
290+
//
291+
// Concretely, the do method will usually be (*Client).do, as all the Resource
292+
// types embed a *Client.
293+
type doer interface {
294+
do(req *http.Request, out any) error
295+
}
296+
297+
// body calls resource.do, passing a *T to do, and returns
298+
// exactly one non-zero value depending on the result of do.
299+
func body[T any](resource doer, req *http.Request) (*T, error) {
300+
var v T
301+
err := resource.do(req, &v)
302+
if err != nil {
303+
return nil, err
304+
}
305+
return &v, nil
306+
}
307+
308+
func (c *Client) do(req *http.Request, out any) error {
289309
res, err := c.HTTP.Do(req)
290310
if err != nil {
291311
return err

v2/contacts.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ func (cr *ContactsResource) Get(ctx context.Context) (*Contacts, error) {
4949
return nil, err
5050
}
5151

52-
var contacts Contacts
53-
return &contacts, cr.do(req, &contacts)
52+
return body[Contacts](cr, req)
5453
}
5554

5655
// Update updates the email for the specified [ContactType] within the tailnet.

v2/device_posture.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@ func (pr *DevicePostureResource) CreateIntegration(ctx context.Context, intg Cre
7474
return nil, err
7575
}
7676

77-
var resp PostureIntegration
78-
return &resp, pr.do(req, &resp)
77+
return body[PostureIntegration](pr, req)
7978
}
8079

8180
// UpdateIntegration updates the existing posture integration identified by id, returning the resulting [PostureIntegration].
@@ -85,8 +84,7 @@ func (pr *DevicePostureResource) UpdateIntegration(ctx context.Context, id strin
8584
return nil, err
8685
}
8786

88-
var resp PostureIntegration
89-
return &resp, pr.do(req, &resp)
87+
return body[PostureIntegration](pr, req)
9088
}
9189

9290
// DeleteIntegration deletes the posture integration identified by id.
@@ -106,6 +104,5 @@ func (pr *DevicePostureResource) GetIntegration(ctx context.Context, id string)
106104
return nil, err
107105
}
108106

109-
var resp PostureIntegration
110-
return &resp, pr.do(req, &resp)
107+
return body[PostureIntegration](pr, req)
111108
}

v2/devices.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@ func (dr *DevicesResource) Get(ctx context.Context, deviceID string) (*Device, e
7171
return nil, err
7272
}
7373

74-
var result Device
75-
return &result, dr.do(req, &result)
74+
return body[Device](dr, req)
7675
}
7776

7877
// List lists every [Device] in the tailnet.
@@ -177,6 +176,5 @@ func (dr *DevicesResource) SubnetRoutes(ctx context.Context, deviceID string) (*
177176
return nil, err
178177
}
179178

180-
var result DeviceRoutes
181-
return &result, dr.do(req, &result)
179+
return body[DeviceRoutes](dr, req)
182180
}

v2/dns.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ func (dr *DNSResource) Preferences(ctx context.Context) (*DNSPreferences, error)
133133
return nil, err
134134
}
135135

136-
var resp DNSPreferences
137-
return &resp, dr.do(req, &resp)
136+
return body[DNSPreferences](dr, req)
138137
}
139138

140139
// SetPreferences replaces the DNS preferences for the tailnet, specifically, the MagicDNS setting. Note that MagicDNS

v2/keys.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ func (kr *KeysResource) Create(ctx context.Context, ckr CreateKeyRequest) (*Key,
5151
return nil, err
5252
}
5353

54-
var key Key
55-
return &key, kr.do(req, &key)
54+
return body[Key](kr, req)
5655
}
5756

5857
// Get returns all information on a [Key] whose identifier matches the one provided. This will not return the
@@ -63,8 +62,7 @@ func (kr *KeysResource) Get(ctx context.Context, id string) (*Key, error) {
6362
return nil, err
6463
}
6564

66-
var key Key
67-
return &key, kr.do(req, &key)
65+
return body[Key](kr, req)
6866
}
6967

7068
// List returns every [Key] within the tailnet. The only fields set for each [Key] will be its identifier.

v2/logging.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ func (lr *LoggingResource) LogstreamConfiguration(ctx context.Context, logType L
5555
return nil, err
5656
}
5757

58-
var logStream LogstreamConfiguration
59-
return &logStream, lr.do(req, &logStream)
58+
return body[LogstreamConfiguration](lr, req)
6059
}
6160

6261
// SetLogstreamConfiguration sets the tailnet's [LogstreamConfiguration] for the given [LogType].

v2/policyfile.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,7 @@ func (pr *PolicyFileResource) Get(ctx context.Context) (*ACL, error) {
115115
return nil, err
116116
}
117117

118-
var resp ACL
119-
return &resp, pr.do(req, &resp)
118+
return body[ACL](pr, req)
120119
}
121120

122121
// Raw retrieves the [ACL] that is currently set for the tailnet as a HuJSON string.

v2/tailnet_settings.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ func (tsr *TailnetSettingsResource) Get(ctx context.Context) (*TailnetSettings,
6060
return nil, err
6161
}
6262

63-
var resp TailnetSettings
64-
return &resp, tsr.do(req, &resp)
63+
return body[TailnetSettings](tsr, req)
6564
}
6665

6766
// Update updates the tailnet settings.

v2/users.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,5 @@ func (ur *UsersResource) Get(ctx context.Context, id string) (*User, error) {
9494
return nil, err
9595
}
9696

97-
var resp User
98-
return &resp, ur.do(req, &resp)
97+
return body[User](ur, req)
9998
}

0 commit comments

Comments
 (0)