Skip to content

Commit 6e94c53

Browse files
authored
Make status code and NGINX error codes on internalError publicly accessible (#489)
1 parent 177be93 commit 6e94c53

File tree

2 files changed

+90
-6
lines changed

2 files changed

+90
-6
lines changed

Diff for: client/nginx.go

+25-6
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ var (
5252
ErrPlusVersionNotFound = errors.New("plus version not found in the input string")
5353
)
5454

55+
// StatusError is an interface that defines our API with consumers of the plus client errors.
56+
// The error will return a http status code and an NGINX error code.
57+
type StatusError interface {
58+
Status() int
59+
Code() string
60+
}
61+
62+
var _ StatusError = (*internalError)(nil)
63+
5564
// NginxClient lets you access NGINX Plus API.
5665
type NginxClient struct {
5766
httpClient *http.Client
@@ -112,8 +121,18 @@ type apiError struct {
112121
}
113122

114123
type internalError struct {
115-
err string
116-
apiError
124+
err string
125+
apiError apiError
126+
}
127+
128+
// Status returns the HTTP status code of the error.
129+
func (internalError *internalError) Status() int {
130+
return internalError.apiError.Status
131+
}
132+
133+
// Status returns the NGINX error code on the response.
134+
func (internalError *internalError) Code() string {
135+
return internalError.apiError.Code
117136
}
118137

119138
// Error allows internalError to match the Error interface.
@@ -1782,7 +1801,7 @@ func (client *NginxClient) GetStreamServerZones(ctx context.Context) (*StreamSer
17821801
if err != nil {
17831802
var ie *internalError
17841803
if errors.As(err, &ie) {
1785-
if ie.Code == pathNotFoundCode {
1804+
if ie.Code() == pathNotFoundCode {
17861805
return &zones, nil
17871806
}
17881807
}
@@ -1808,7 +1827,7 @@ func (client *NginxClient) GetStreamUpstreams(ctx context.Context) (*StreamUpstr
18081827
if err != nil {
18091828
var ie *internalError
18101829
if errors.As(err, &ie) {
1811-
if ie.Code == pathNotFoundCode {
1830+
if ie.Code() == pathNotFoundCode {
18121831
return &upstreams, nil
18131832
}
18141833
}
@@ -1824,7 +1843,7 @@ func (client *NginxClient) GetStreamZoneSync(ctx context.Context) (*StreamZoneSy
18241843
if err != nil {
18251844
var ie *internalError
18261845
if errors.As(err, &ie) {
1827-
if ie.Code == pathNotFoundCode {
1846+
if ie.Code() == pathNotFoundCode {
18281847
return nil, nil
18291848
}
18301849
}
@@ -2137,7 +2156,7 @@ func (client *NginxClient) GetStreamConnectionsLimit(ctx context.Context) (*Stre
21372156
if err != nil {
21382157
var ie *internalError
21392158
if errors.As(err, &ie) {
2140-
if ie.Code == pathNotFoundCode {
2159+
if ie.Code() == pathNotFoundCode {
21412160
return &limitConns, nil
21422161
}
21432162
}

Diff for: client/nginx_test.go

+65
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package client
33
import (
44
"context"
55
"encoding/json"
6+
"errors"
67
"net/http"
78
"net/http/httptest"
89
"reflect"
@@ -1438,6 +1439,70 @@ func TestUpdateStreamServers(t *testing.T) {
14381439
}
14391440
}
14401441

1442+
func TestInternalError(t *testing.T) {
1443+
t.Parallel()
1444+
1445+
// mimic a user-defined interface type
1446+
type TestStatusError interface {
1447+
Status() int
1448+
Code() string
1449+
}
1450+
1451+
//nolint // ignore golangci-lint err113 sugggestion to create package level static error
1452+
anotherErr := errors.New("another error")
1453+
1454+
notFoundErr := &internalError{
1455+
err: "not found error",
1456+
apiError: apiError{
1457+
Text: "not found error",
1458+
Status: http.StatusNotFound,
1459+
Code: "not found code",
1460+
},
1461+
}
1462+
1463+
testcases := map[string]struct {
1464+
inputErr error
1465+
expectedCode string
1466+
expectedStatus int
1467+
}{
1468+
"simple not found": {
1469+
inputErr: notFoundErr,
1470+
expectedStatus: http.StatusNotFound,
1471+
expectedCode: "not found code",
1472+
},
1473+
"not found joined with another error": {
1474+
inputErr: errors.Join(notFoundErr, anotherErr),
1475+
expectedStatus: http.StatusNotFound,
1476+
expectedCode: "not found code",
1477+
},
1478+
"not found wrapped with another error": {
1479+
inputErr: notFoundErr.Wrap("some error"),
1480+
expectedStatus: http.StatusNotFound,
1481+
expectedCode: "not found code",
1482+
},
1483+
}
1484+
1485+
for name, tc := range testcases {
1486+
t.Run(name, func(t *testing.T) {
1487+
t.Parallel()
1488+
1489+
var se TestStatusError
1490+
ok := errors.As(tc.inputErr, &se)
1491+
if !ok {
1492+
t.Fatalf("could not cast error %v as StatusError", tc.inputErr)
1493+
}
1494+
1495+
if se.Status() != tc.expectedStatus {
1496+
t.Fatalf("expected status %d, got status %d", tc.expectedStatus, se.Status())
1497+
}
1498+
1499+
if se.Code() != tc.expectedCode {
1500+
t.Fatalf("expected code %s, got code %s", tc.expectedCode, se.Code())
1501+
}
1502+
})
1503+
}
1504+
}
1505+
14411506
type response struct {
14421507
servers interface{}
14431508
statusCode int

0 commit comments

Comments
 (0)