Skip to content

Commit 5e2ed68

Browse files
committed
feat(pkg): standardize errors on internal http client
1 parent 13a219f commit 5e2ed68

File tree

8 files changed

+149
-74
lines changed

8 files changed

+149
-74
lines changed

pkg/api/internalclient/billing.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package internalclient
22

33
import (
44
"context"
5-
"net/http"
5+
"errors"
66

77
"github.com/shellhub-io/shellhub/pkg/models"
88
)
@@ -18,6 +18,8 @@ type billingAPI interface {
1818
BillingEvaluate(ctx context.Context, tenantID string) (*models.BillingEvaluation, int, error)
1919
}
2020

21+
var ErrBillingRequestFailed = errors.New("billing request failed")
22+
2123
func (c *client) BillingReport(ctx context.Context, tenant string, action string) (int, error) {
2224
res, err := c.http.
2325
R().
@@ -26,7 +28,8 @@ func (c *client) BillingReport(ctx context.Context, tenant string, action string
2628
SetQueryParam("action", action).
2729
Post(c.Config.EnterpriseBaseURL + "/internal/billing/report")
2830
if err != nil {
29-
return http.StatusInternalServerError, err
31+
// TODO: It shouldn't return the status code.
32+
return res.StatusCode(), errors.Join(ErrBillingRequestFailed, err)
3033
}
3134

3235
return res.StatusCode(), nil
@@ -42,7 +45,7 @@ func (c *client) BillingEvaluate(ctx context.Context, tenantID string) (*models.
4245
SetResult(&eval).
4346
Post(c.Config.EnterpriseBaseURL + "/internal/billing/evaluate")
4447
if err != nil {
45-
return eval, resp.StatusCode(), err
48+
return nil, resp.StatusCode(), errors.Join(ErrBillingRequestFailed, err)
4649
}
4750

4851
return eval, resp.StatusCode(), nil

pkg/api/internalclient/client.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
log "github.com/sirupsen/logrus"
1212
)
1313

14+
var ErrClientRequestFailed = errors.New("client request failed")
15+
1416
//go:generate mockery --name=Client --filename=internalclient.go
1517
type Client interface {
1618
deviceAPI
@@ -73,7 +75,7 @@ func NewClient(opts ...clientOption) (Client, error) {
7375

7476
for _, opt := range opts {
7577
if err := opt(c); err != nil {
76-
return nil, err
78+
return nil, errors.Join(ErrClientRequestFailed, err)
7779
}
7880
}
7981

pkg/api/internalclient/device.go

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type deviceAPI interface {
2424
DevicesHeartbeat(ctx context.Context, uid string) error
2525

2626
// Lookup performs a lookup operation based on the provided parameters.
27-
Lookup(ctx context.Context, lookup map[string]string) (string, []error)
27+
Lookup(ctx context.Context, lookup map[string]string) (string, error)
2828

2929
// DeviceLookup performs a lookup operation based on the provided parameters.
3030
DeviceLookup(ctx context.Context, tenantID, name string) (*models.Device, error)
@@ -33,14 +33,16 @@ type deviceAPI interface {
3333
LookupWebEndpoints(ctx context.Context, address string) (*WebEndpoint, error)
3434
}
3535

36+
var ErrDeviceRequestFailed = errors.New("device request failed")
37+
3638
func (c *client) DevicesOffline(ctx context.Context, uid string) error {
3739
_, err := c.http.
3840
R().
3941
SetContext(ctx).
4042
SetPathParam("uid", uid).
4143
Post(c.Config.APIBaseURL + "/internal/devices/{uid}/offline")
4244
if err != nil {
43-
return err
45+
return errors.Join(ErrDeviceRequestFailed, err)
4446
}
4547

4648
return nil
@@ -50,27 +52,35 @@ func (c *client) DevicesHeartbeat(ctx context.Context, uid string) error {
5052
return c.worker.SubmitToBatch(ctx, worker.TaskPattern("api:heartbeat"), []byte(uid))
5153
}
5254

53-
func (c *client) Lookup(ctx context.Context, lookup map[string]string) (string, []error) {
55+
var ErrLookupFailed = errors.New("lookup failed")
56+
57+
func (c *client) Lookup(ctx context.Context, lookup map[string]string) (string, error) {
5458
var device struct {
5559
UID string `json:"uid"`
5660
}
5761

58-
resp, _ := c.http.
62+
resp, err := c.http.
5963
R().
6064
SetContext(ctx).
6165
SetQueryParams(lookup).
6266
SetResult(&device).
6367
Get(c.Config.APIBaseURL + "/internal/lookup")
68+
if err != nil {
69+
return "", errors.Join(ErrDeviceRequestFailed, err)
70+
}
6471

6572
if resp.StatusCode() != http.StatusOK {
66-
return "", []error{errors.New("lookup failed")}
73+
return "", ErrLookupFailed
6774
}
6875

6976
return device.UID, nil
7077
}
7178

79+
var ErrDeviceLookupFailed = errors.New("device lookup failed")
80+
7281
func (c *client) DeviceLookup(ctx context.Context, tenantID, name string) (*models.Device, error) {
7382
device := new(models.Device)
83+
7484
resp, err := c.http.
7585
R().
7686
SetContext(ctx).
@@ -79,33 +89,39 @@ func (c *client) DeviceLookup(ctx context.Context, tenantID, name string) (*mode
7989
SetResult(&device).
8090
Get(c.Config.APIBaseURL + "/internal/device/lookup")
8191
if err != nil {
82-
return nil, ErrConnectionFailed
92+
return nil, errors.Join(ErrDeviceRequestFailed, err)
8393
}
8494

85-
switch resp.StatusCode() {
86-
case http.StatusOK:
87-
return device, nil
88-
case http.StatusNotFound:
89-
return nil, ErrNotFound
90-
case http.StatusForbidden:
91-
return nil, ErrForbidden
92-
default:
93-
return nil, ErrUnknown
95+
if resp.StatusCode() != http.StatusOK {
96+
return nil, ErrDeviceLookupFailed
9497
}
98+
99+
return device, nil
95100
}
96101

102+
var ErrListDevicesFailed = errors.New("list devices failed")
103+
97104
func (c *client) ListDevices(ctx context.Context) ([]models.Device, error) {
98105
list := []models.Device{}
99106

100-
_, err := c.http.
107+
resp, err := c.http.
101108
R().
102109
SetContext(ctx).
103110
SetResult(list).
104111
Get(c.Config.APIBaseURL + "/api/devices")
112+
if err != nil {
113+
return nil, errors.Join(ErrDeviceRequestFailed, err)
114+
}
115+
116+
if resp.StatusCode() != http.StatusOK {
117+
return nil, ErrListDevicesFailed
118+
}
105119

106-
return list, err
120+
return list, nil
107121
}
108122

123+
var ErrGetDeviceFailed = errors.New("get device failed")
124+
109125
func (c *client) GetDevice(ctx context.Context, uid string) (*models.Device, error) {
110126
device := new(models.Device)
111127
resp, err := c.http.
@@ -114,17 +130,14 @@ func (c *client) GetDevice(ctx context.Context, uid string) (*models.Device, err
114130
SetResult(&device).
115131
Get(c.Config.APIBaseURL + "/api/devices/{uid}")
116132
if err != nil {
117-
return nil, ErrConnectionFailed
133+
return nil, errors.Join(ErrDeviceRequestFailed, err)
118134
}
119135

120-
switch resp.StatusCode() {
121-
case 400:
122-
return nil, ErrNotFound
123-
case 200:
124-
return device, nil
125-
default:
126-
return nil, ErrUnknown
136+
if resp.StatusCode() != http.StatusOK {
137+
return nil, ErrGetDeviceFailed
127138
}
139+
140+
return device, nil
128141
}
129142

130143
type WebEndpoint struct {
@@ -139,26 +152,26 @@ type WebEndpoint struct {
139152
CreatedAt time.Time `json:"time" bson:"time"`
140153
}
141154

155+
var (
156+
ErrWebEndpointRequestFailed = errors.New("web endpoint request failed")
157+
ErrWebEndpointForbidden = errors.New("web endpoint access forbidden")
158+
)
159+
142160
func (c *client) LookupWebEndpoints(ctx context.Context, address string) (*WebEndpoint, error) {
143-
var tunnel *WebEndpoint
161+
var endpoint *WebEndpoint
144162
resp, err := c.http.
145163
R().
146164
SetContext(ctx).
147165
SetPathParam("address", address).
148-
SetResult(&tunnel).
166+
SetResult(&endpoint).
149167
Get(c.Config.EnterpriseBaseURL + "/internal/web-endpoints/{address}")
150168
if err != nil {
151-
return nil, ErrConnectionFailed
169+
return nil, errors.Join(ErrWebEndpointRequestFailed, err)
152170
}
153171

154-
switch resp.StatusCode() {
155-
case 404:
156-
return nil, ErrNotFound
157-
case 403:
158-
return nil, ErrForbidden
159-
case 200:
160-
return tunnel, nil
161-
default:
162-
return nil, ErrUnknown
172+
if resp.StatusCode() != http.StatusOK {
173+
return nil, ErrWebEndpointForbidden
163174
}
175+
176+
return endpoint, nil
164177
}

pkg/api/internalclient/firewall.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ type firewallAPI interface {
1414
}
1515

1616
var (
17-
ErrFirewallConnection = errors.New("failed to make the request to evaluate the firewall")
18-
ErrFirewallBlock = errors.New("a firewall rule prohibit this connection")
17+
// ErrFirewallEvaluationRequest is returned when the firewall evaluation request fails for any reason.
18+
ErrFirewallEvaluationRequest = errors.New("failed to evaluate the firewall")
19+
20+
// ErrFirewallBlock is returned when a firewall rule prohibits the connection.
21+
ErrFirewallBlock = errors.New("a firewall rule prohibit this connection")
1922
)
2023

2124
func (c *client) FirewallEvaluate(ctx context.Context, lookup map[string]string) error {
@@ -25,7 +28,7 @@ func (c *client) FirewallEvaluate(ctx context.Context, lookup map[string]string)
2528
SetQueryParams(lookup).
2629
Get(c.Config.EnterpriseBaseURL + "/internal/firewall/rules/evaluate")
2730
if err != nil {
28-
return ErrFirewallConnection
31+
return errors.Join(ErrFirewallEvaluationRequest, err)
2932
}
3033

3134
if resp.StatusCode() != http.StatusOK {

pkg/api/internalclient/namespace.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package internalclient
22

33
import (
44
"context"
5+
"errors"
56
"net/http"
67

78
"github.com/shellhub-io/shellhub/pkg/models"
@@ -19,6 +20,13 @@ type namespaceAPI interface {
1920
InviteMember(ctx context.Context, tenantID, userID, forwardedHost string) error
2021
}
2122

23+
var (
24+
// ErrNamespaceLookupRequest indicates that the namespace lookup request failed.
25+
ErrNamespaceLookupRequest = errors.New("namespace lookup request failed")
26+
// ErrNamespaceLookupFailed indicates that the namespace lookup operation failed.
27+
ErrNamespaceLookupFailed = errors.New("namespace lookup failed")
28+
)
29+
2230
func (c *client) NamespaceLookup(ctx context.Context, tenant string) (*models.Namespace, error) {
2331
namespace := new(models.Namespace)
2432
res, err := c.http.
@@ -28,11 +36,11 @@ func (c *client) NamespaceLookup(ctx context.Context, tenant string) (*models.Na
2836
SetResult(namespace).
2937
Get(c.Config.APIBaseURL + "/api/namespaces/{tenant}")
3038
if err != nil {
31-
return nil, err
39+
return nil, errors.Join(ErrNamespaceLookupRequest, err)
3240
}
3341

3442
if res.StatusCode() != http.StatusOK {
35-
return nil, err
43+
return nil, ErrNamespaceLookupFailed
3644
}
3745

3846
return namespace, nil

0 commit comments

Comments
 (0)