Skip to content

Commit 4f5fccb

Browse files
committed
Refactor NGIXN Client to use options
1 parent 91d142e commit 4f5fccb

File tree

4 files changed

+158
-62
lines changed

4 files changed

+158
-62
lines changed

client/nginx.go

Lines changed: 68 additions & 34 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.
@@ -494,35 +497,66 @@ type HTTPLimitConnections map[string]LimitConnection
494497
// StreamLimitConnections represents limit connections related stats
495498
type StreamLimitConnections map[string]LimitConnection
496499

497-
// NewNginxClient creates an NginxClient with the latest supported version.
498-
func NewNginxClient(httpClient *http.Client, apiEndpoint string) (*NginxClient, error) {
499-
return NewNginxClientWithVersion(httpClient, apiEndpoint, APIVersion)
500+
// WithHTTPClient sets the HTTP client to use for accessing the API.
501+
func WithHTTPClient(httpClient *http.Client) Option {
502+
return func(o *NginxClient) {
503+
o.httpClient = httpClient
504+
}
500505
}
501506

502-
// NewNginxClientWithVersion creates an NginxClient with the given version of NGINX Plus API.
503-
func NewNginxClientWithVersion(httpClient *http.Client, apiEndpoint string, version int) (*NginxClient, error) {
504-
if !versionSupported(version) {
505-
return nil, fmt.Errorf("API version %v is not supported by the client", version)
507+
// WithAPIVersion sets the API version to use for accessing the API.
508+
func WithAPIVersion(apiVersion int) Option {
509+
return func(o *NginxClient) {
510+
o.apiVersion = apiVersion
506511
}
507-
versions, err := getAPIVersions(httpClient, apiEndpoint)
508-
if err != nil {
509-
return nil, fmt.Errorf("error accessing the API: %w", err)
512+
}
513+
514+
// WithCheckAPI sets the flag to check the API version of the server.
515+
func WithCheckAPI() Option {
516+
return func(o *NginxClient) {
517+
o.checkAPI = true
510518
}
511-
found := false
512-
for _, v := range *versions {
513-
if v == version {
514-
found = true
515-
break
516-
}
519+
}
520+
521+
// NewNginxClient creates a new NginxClient.
522+
func NewNginxClient(apiEndpoint string, opts ...Option) (*NginxClient, error) {
523+
c := &NginxClient{
524+
httpClient: http.DefaultClient,
525+
apiEndpoint: apiEndpoint,
526+
apiVersion: APIVersion,
527+
checkAPI: false,
517528
}
518-
if !found {
519-
return nil, ErrUnsupportedVer
529+
530+
for _, opt := range opts {
531+
opt(c)
520532
}
521-
return &NginxClient{
522-
apiEndpoint: apiEndpoint,
523-
httpClient: httpClient,
524-
version: version,
525-
}, nil
533+
534+
if c.httpClient == nil {
535+
return nil, fmt.Errorf("http client is not set")
536+
}
537+
538+
if !versionSupported(c.apiVersion) {
539+
return nil, fmt.Errorf("API version %v is not supported by the client", c.apiVersion)
540+
}
541+
542+
if c.checkAPI {
543+
versions, err := getAPIVersions(c.httpClient, apiEndpoint)
544+
if err != nil {
545+
return nil, fmt.Errorf("error accessing the API: %w", err)
546+
}
547+
found := false
548+
for _, v := range *versions {
549+
if v == c.apiVersion {
550+
found = true
551+
break
552+
}
553+
}
554+
if !found {
555+
return nil, fmt.Errorf("API version %v is not supported by the server", c.apiVersion)
556+
}
557+
}
558+
559+
return c, nil
526560
}
527561

528562
func versionSupported(n int) bool {
@@ -793,7 +827,7 @@ func (client *NginxClient) get(path string, data interface{}) error {
793827
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
794828
defer cancel()
795829

796-
url := fmt.Sprintf("%v/%v/%v", client.apiEndpoint, client.version, path)
830+
url := fmt.Sprintf("%v/%v/%v", client.apiEndpoint, client.apiVersion, path)
797831

798832
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
799833
if err != nil {
@@ -827,7 +861,7 @@ func (client *NginxClient) post(path string, input interface{}) error {
827861
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
828862
defer cancel()
829863

830-
url := fmt.Sprintf("%v/%v/%v", client.apiEndpoint, client.version, path)
864+
url := fmt.Sprintf("%v/%v/%v", client.apiEndpoint, client.apiVersion, path)
831865

832866
jsonInput, err := json.Marshal(input)
833867
if err != nil {
@@ -859,7 +893,7 @@ func (client *NginxClient) delete(path string, expectedStatusCode int) error {
859893
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
860894
defer cancel()
861895

862-
path = fmt.Sprintf("%v/%v/%v/", client.apiEndpoint, client.version, path)
896+
path = fmt.Sprintf("%v/%v/%v/", client.apiEndpoint, client.apiVersion, path)
863897

864898
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, path, nil)
865899
if err != nil {
@@ -884,7 +918,7 @@ func (client *NginxClient) patch(path string, input interface{}, expectedStatusC
884918
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
885919
defer cancel()
886920

887-
path = fmt.Sprintf("%v/%v/%v/", client.apiEndpoint, client.version, path)
921+
path = fmt.Sprintf("%v/%v/%v/", client.apiEndpoint, client.apiVersion, path)
888922

889923
jsonInput, err := json.Marshal(input)
890924
if err != nil {
@@ -1339,7 +1373,7 @@ func (client *NginxClient) GetStreamZoneSync() (*StreamZoneSync, error) {
13391373
// GetLocationZones returns http/location_zones stats.
13401374
func (client *NginxClient) GetLocationZones() (*LocationZones, error) {
13411375
var locationZones LocationZones
1342-
if client.version < 5 {
1376+
if client.apiVersion < 5 {
13431377
return &locationZones, nil
13441378
}
13451379
err := client.get("http/location_zones", &locationZones)
@@ -1353,7 +1387,7 @@ func (client *NginxClient) GetLocationZones() (*LocationZones, error) {
13531387
// GetResolvers returns Resolvers stats.
13541388
func (client *NginxClient) GetResolvers() (*Resolvers, error) {
13551389
var resolvers Resolvers
1356-
if client.version < 5 {
1390+
if client.apiVersion < 5 {
13571391
return &resolvers, nil
13581392
}
13591393
err := client.get("resolvers", &resolvers)
@@ -1576,7 +1610,7 @@ func (client *NginxClient) UpdateStreamServer(upstream string, server StreamUpst
15761610

15771611
// Version returns client's current N+ API version.
15781612
func (client *NginxClient) Version() int {
1579-
return client.version
1613+
return client.apiVersion
15801614
}
15811615

15821616
func addPortToServer(server string) string {
@@ -1598,7 +1632,7 @@ func addPortToServer(server string) string {
15981632
// GetHTTPLimitReqs returns http/limit_reqs stats.
15991633
func (client *NginxClient) GetHTTPLimitReqs() (*HTTPLimitRequests, error) {
16001634
var limitReqs HTTPLimitRequests
1601-
if client.version < 6 {
1635+
if client.apiVersion < 6 {
16021636
return &limitReqs, nil
16031637
}
16041638
err := client.get("http/limit_reqs", &limitReqs)
@@ -1611,7 +1645,7 @@ func (client *NginxClient) GetHTTPLimitReqs() (*HTTPLimitRequests, error) {
16111645
// GetHTTPConnectionsLimit returns http/limit_conns stats.
16121646
func (client *NginxClient) GetHTTPConnectionsLimit() (*HTTPLimitConnections, error) {
16131647
var limitConns HTTPLimitConnections
1614-
if client.version < 6 {
1648+
if client.apiVersion < 6 {
16151649
return &limitConns, nil
16161650
}
16171651
err := client.get("http/limit_conns", &limitConns)
@@ -1624,7 +1658,7 @@ func (client *NginxClient) GetHTTPConnectionsLimit() (*HTTPLimitConnections, err
16241658
// GetStreamConnectionsLimit returns stream/limit_conns stats.
16251659
func (client *NginxClient) GetStreamConnectionsLimit() (*StreamLimitConnections, error) {
16261660
var limitConns StreamLimitConnections
1627-
if client.version < 6 {
1661+
if client.apiVersion < 6 {
16281662
return &limitConns, nil
16291663
}
16301664
err := client.get("stream/limit_conns", &limitConns)

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)