Skip to content

Commit afe2a4f

Browse files
committed
Refactor NGINX Client to use options
1 parent 80901b0 commit afe2a4f

File tree

4 files changed

+159
-63
lines changed

4 files changed

+159
-63
lines changed

client/nginx.go

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,14 @@ var ErrUnsupportedVer = errors.New("API version of the client is not supported b
4141

4242
// NginxClient lets you access NGINX Plus API.
4343
type NginxClient struct {
44-
version int
44+
apiVersion int
4545
apiEndpoint string
4646
httpClient *http.Client
47+
checkAPI bool
4748
}
4849

50+
type Option func(*NginxClient)
51+
4952
type versions []int
5053

5154
// UpstreamServer lets you configure HTTP upstreams.
@@ -508,35 +511,66 @@ type WorkersHTTP struct {
508511
HTTPRequests HTTPRequests `json:"requests"`
509512
}
510513

511-
// NewNginxClient creates an NginxClient with the latest supported version.
512-
func NewNginxClient(httpClient *http.Client, apiEndpoint string) (*NginxClient, error) {
513-
return NewNginxClientWithVersion(httpClient, apiEndpoint, APIVersion)
514+
// WithHTTPClient sets the HTTP client to use for accessing the API.
515+
func WithHTTPClient(httpClient *http.Client) Option {
516+
return func(o *NginxClient) {
517+
o.httpClient = httpClient
518+
}
514519
}
515520

516-
// NewNginxClientWithVersion creates an NginxClient with the given version of NGINX Plus API.
517-
func NewNginxClientWithVersion(httpClient *http.Client, apiEndpoint string, version int) (*NginxClient, error) {
518-
if !versionSupported(version) {
519-
return nil, fmt.Errorf("API version %v is not supported by the client", version)
521+
// WithAPIVersion sets the API version to use for accessing the API.
522+
func WithAPIVersion(apiVersion int) Option {
523+
return func(o *NginxClient) {
524+
o.apiVersion = apiVersion
520525
}
521-
versions, err := getAPIVersions(httpClient, apiEndpoint)
522-
if err != nil {
523-
return nil, fmt.Errorf("error accessing the API: %w", err)
526+
}
527+
528+
// WithCheckAPI sets the flag to check the API version of the server.
529+
func WithCheckAPI() Option {
530+
return func(o *NginxClient) {
531+
o.checkAPI = true
524532
}
525-
found := false
526-
for _, v := range *versions {
527-
if v == version {
528-
found = true
529-
break
530-
}
533+
}
534+
535+
// NewNginxClient creates a new NginxClient.
536+
func NewNginxClient(apiEndpoint string, opts ...Option) (*NginxClient, error) {
537+
c := &NginxClient{
538+
httpClient: http.DefaultClient,
539+
apiEndpoint: apiEndpoint,
540+
apiVersion: APIVersion,
541+
checkAPI: false,
531542
}
532-
if !found {
533-
return nil, ErrUnsupportedVer
543+
544+
for _, opt := range opts {
545+
opt(c)
534546
}
535-
return &NginxClient{
536-
apiEndpoint: apiEndpoint,
537-
httpClient: httpClient,
538-
version: version,
539-
}, nil
547+
548+
if c.httpClient == nil {
549+
return nil, fmt.Errorf("http client is not set")
550+
}
551+
552+
if !versionSupported(c.apiVersion) {
553+
return nil, fmt.Errorf("API version %v is not supported by the client", c.apiVersion)
554+
}
555+
556+
if c.checkAPI {
557+
versions, err := getAPIVersions(c.httpClient, apiEndpoint)
558+
if err != nil {
559+
return nil, fmt.Errorf("error accessing the API: %w", err)
560+
}
561+
found := false
562+
for _, v := range *versions {
563+
if v == c.apiVersion {
564+
found = true
565+
break
566+
}
567+
}
568+
if !found {
569+
return nil, fmt.Errorf("API version %v is not supported by the server", c.apiVersion)
570+
}
571+
}
572+
573+
return c, nil
540574
}
541575

542576
func versionSupported(n int) bool {
@@ -807,7 +841,7 @@ func (client *NginxClient) get(path string, data interface{}) error {
807841
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
808842
defer cancel()
809843

810-
url := fmt.Sprintf("%v/%v/%v", client.apiEndpoint, client.version, path)
844+
url := fmt.Sprintf("%v/%v/%v", client.apiEndpoint, client.apiVersion, path)
811845

812846
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
813847
if err != nil {
@@ -841,7 +875,7 @@ func (client *NginxClient) post(path string, input interface{}) error {
841875
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
842876
defer cancel()
843877

844-
url := fmt.Sprintf("%v/%v/%v", client.apiEndpoint, client.version, path)
878+
url := fmt.Sprintf("%v/%v/%v", client.apiEndpoint, client.apiVersion, path)
845879

846880
jsonInput, err := json.Marshal(input)
847881
if err != nil {
@@ -873,7 +907,7 @@ func (client *NginxClient) delete(path string, expectedStatusCode int) error {
873907
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
874908
defer cancel()
875909

876-
path = fmt.Sprintf("%v/%v/%v/", client.apiEndpoint, client.version, path)
910+
path = fmt.Sprintf("%v/%v/%v/", client.apiEndpoint, client.apiVersion, path)
877911

878912
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, path, nil)
879913
if err != nil {
@@ -898,7 +932,7 @@ func (client *NginxClient) patch(path string, input interface{}, expectedStatusC
898932
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
899933
defer cancel()
900934

901-
path = fmt.Sprintf("%v/%v/%v/", client.apiEndpoint, client.version, path)
935+
path = fmt.Sprintf("%v/%v/%v/", client.apiEndpoint, client.apiVersion, path)
902936

903937
jsonInput, err := json.Marshal(input)
904938
if err != nil {
@@ -1359,7 +1393,7 @@ func (client *NginxClient) GetStreamZoneSync() (*StreamZoneSync, error) {
13591393
// GetLocationZones returns http/location_zones stats.
13601394
func (client *NginxClient) GetLocationZones() (*LocationZones, error) {
13611395
var locationZones LocationZones
1362-
if client.version < 5 {
1396+
if client.apiVersion < 5 {
13631397
return &locationZones, nil
13641398
}
13651399
err := client.get("http/location_zones", &locationZones)
@@ -1373,7 +1407,7 @@ func (client *NginxClient) GetLocationZones() (*LocationZones, error) {
13731407
// GetResolvers returns Resolvers stats.
13741408
func (client *NginxClient) GetResolvers() (*Resolvers, error) {
13751409
var resolvers Resolvers
1376-
if client.version < 5 {
1410+
if client.apiVersion < 5 {
13771411
return &resolvers, nil
13781412
}
13791413
err := client.get("resolvers", &resolvers)
@@ -1596,7 +1630,7 @@ func (client *NginxClient) UpdateStreamServer(upstream string, server StreamUpst
15961630

15971631
// Version returns client's current N+ API version.
15981632
func (client *NginxClient) Version() int {
1599-
return client.version
1633+
return client.apiVersion
16001634
}
16011635

16021636
func addPortToServer(server string) string {
@@ -1618,7 +1652,7 @@ func addPortToServer(server string) string {
16181652
// GetHTTPLimitReqs returns http/limit_reqs stats.
16191653
func (client *NginxClient) GetHTTPLimitReqs() (*HTTPLimitRequests, error) {
16201654
var limitReqs HTTPLimitRequests
1621-
if client.version < 6 {
1655+
if client.apiVersion < 6 {
16221656
return &limitReqs, nil
16231657
}
16241658
err := client.get("http/limit_reqs", &limitReqs)
@@ -1631,7 +1665,7 @@ func (client *NginxClient) GetHTTPLimitReqs() (*HTTPLimitRequests, error) {
16311665
// GetHTTPConnectionsLimit returns http/limit_conns stats.
16321666
func (client *NginxClient) GetHTTPConnectionsLimit() (*HTTPLimitConnections, error) {
16331667
var limitConns HTTPLimitConnections
1634-
if client.version < 6 {
1668+
if client.apiVersion < 6 {
16351669
return &limitConns, nil
16361670
}
16371671
err := client.get("http/limit_conns", &limitConns)
@@ -1644,7 +1678,7 @@ func (client *NginxClient) GetHTTPConnectionsLimit() (*HTTPLimitConnections, err
16441678
// GetStreamConnectionsLimit returns stream/limit_conns stats.
16451679
func (client *NginxClient) GetStreamConnectionsLimit() (*StreamLimitConnections, error) {
16461680
var limitConns StreamLimitConnections
1647-
if client.version < 6 {
1681+
if client.apiVersion < 6 {
16481682
return &limitConns, nil
16491683
}
16501684
err := client.get("stream/limit_conns", &limitConns)
@@ -1663,7 +1697,7 @@ func (client *NginxClient) GetStreamConnectionsLimit() (*StreamLimitConnections,
16631697
// GetWorkers returns workers stats.
16641698
func (client *NginxClient) GetWorkers() ([]*Workers, error) {
16651699
var workers []*Workers
1666-
if client.version < 9 {
1700+
if client.apiVersion < 9 {
16671701
return workers, nil
16681702
}
16691703
err := client.get("workers", &workers)

client/nginx_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package client
22

33
import (
4+
"net/http"
5+
"net/http/httptest"
46
"reflect"
57
"testing"
68
)
@@ -518,3 +520,72 @@ func TestHaveSameParametersForStream(t *testing.T) {
518520
}
519521
}
520522
}
523+
524+
func TestClientWithCheckAPI(t *testing.T) {
525+
// Create a test server that returns supported API versions
526+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
527+
_, err := w.Write([]byte(`[4, 5, 6, 7]`))
528+
if err != nil {
529+
t.Fatalf("unexpected error: %v", err)
530+
}
531+
}))
532+
defer ts.Close()
533+
534+
// Test creating a new client with a supported API version on the server
535+
client, err := NewNginxClient(ts.URL, WithAPIVersion(7), WithCheckAPI())
536+
if err != nil {
537+
t.Fatalf("unexpected error: %v", err)
538+
}
539+
if client == nil {
540+
t.Fatalf("client is nil")
541+
}
542+
543+
// Test creating a new client with an unsupported API version on the server
544+
client, err = NewNginxClient(ts.URL, WithAPIVersion(8), WithCheckAPI())
545+
if err == nil {
546+
t.Fatalf("expected error, but got nil")
547+
}
548+
if client != nil {
549+
t.Fatalf("expected client to be nil, but got %v", client)
550+
}
551+
}
552+
553+
func TestClientWithAPIVersion(t *testing.T) {
554+
// Test creating a new client with a supported API version on the client
555+
client, err := NewNginxClient("http://api-url", WithAPIVersion(8))
556+
if err != nil {
557+
t.Fatalf("unexpected error: %v", err)
558+
}
559+
if client == nil {
560+
t.Fatalf("client is nil")
561+
}
562+
563+
// Test creating a new client with an unsupported API version on the client
564+
client, err = NewNginxClient("http://api-url", WithAPIVersion(3))
565+
if err == nil {
566+
t.Fatalf("expected error, but got nil")
567+
}
568+
if client != nil {
569+
t.Fatalf("expected client to be nil, but got %v", client)
570+
}
571+
}
572+
573+
func TestClientWithHTTPClient(t *testing.T) {
574+
// Test creating a new client passing a custom HTTP client
575+
client, err := NewNginxClient("http://api-url", WithHTTPClient(&http.Client{}))
576+
if err != nil {
577+
t.Fatalf("unexpected error: %v", err)
578+
}
579+
if client == nil {
580+
t.Fatalf("client is nil")
581+
}
582+
583+
// Test creating a new client passing a nil HTTP client
584+
client, err = NewNginxClient("http://api-url", WithHTTPClient(nil))
585+
if err == nil {
586+
t.Fatalf("expected error, but got nil")
587+
}
588+
if client != nil {
589+
t.Fatalf("expected client to be nil, but got %v", client)
590+
}
591+
}

tests/client_no_stream_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package tests
22

33
import (
4-
"net/http"
54
"testing"
65

76
"github.com/nginxinc/nginx-plus-go-client/client"
@@ -13,8 +12,7 @@ import (
1312
// The API returns a special error code that we can use to determine if the API
1413
// is misconfigured or of the stream block is missing.
1514
func TestStatsNoStream(t *testing.T) {
16-
httpClient := &http.Client{}
17-
c, err := client.NewNginxClient(httpClient, helpers.GetAPIEndpoint())
15+
c, err := client.NewNginxClient(helpers.GetAPIEndpoint())
1816
if err != nil {
1917
t.Fatalf("Error connecting to nginx: %v", err)
2018
}

0 commit comments

Comments
 (0)