func (client *NginxClient) DeleteHTTPServer(upstream string, server string) error {
	id, err := client.getIDOfHTTPServer(upstream, server)
	if err != nil {
		return fmt.Errorf("failed to remove %v server from  %v upstream: %w", server, upstream, err)
	}
	if id == -1 {
		return fmt.Errorf("failed to remove %v server from %v upstream: server doesn't exist", server, upstream)
	}
	path := fmt.Sprintf("http/upstreams/%v/servers/%v", upstream, id)
	err = client.delete(path, http.StatusOK)
	if err != nil {
		return fmt.Errorf("failed to remove %v server from %v upstream: %w", server, upstream, err)
	}
	return nil
}
DeleteHTTPServer the server from the upstream.
package client
import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"reflect"
	"strings"
	"time"
)
const (
	APIVersion = 5
	pathNotFoundCode  = "PathNotFound"
	streamContext     = true
	httpContext       = false
	defaultServerPort = "80"
)
var (
	supportedAPIVersions = versions{4, 5}
	defaultMaxConns    = 0
	defaultMaxFails    = 1
	defaultFailTimeout = "10s"
	defaultSlowStart   = "0s"
	defaultBackup      = false
	defaultDown        = false
	defaultWeight      = 1
)
var ErrUnsupportedVer = errors.New("API version of the client is not supported by running NGINX Plus")
type NginxClient struct {
	version     int
	apiEndpoint string
	httpClient  *http.Client
}
type versions []int
type UpstreamServer struct {
	ID          int    `json:"id,omitempty"`
	Server      string `json:"server"`
	MaxConns    *int   `json:"max_conns,omitempty"`
	MaxFails    *int   `json:"max_fails,omitempty"`
	FailTimeout string `json:"fail_timeout,omitempty"`
	SlowStart   string `json:"slow_start,omitempty"`
	Route       string `json:"route,omitempty"`
	Backup      *bool  `json:"backup,omitempty"`
	Down        *bool  `json:"down,omitempty"`
	Drain       bool   `json:"drain,omitempty"`
	Weight      *int   `json:"weight,omitempty"`
	Service     string `json:"service,omitempty"`
}
type StreamUpstreamServer struct {
	ID          int    `json:"id,omitempty"`
	Server      string `json:"server"`
	MaxConns    *int   `json:"max_conns,omitempty"`
	MaxFails    *int   `json:"max_fails,omitempty"`
	FailTimeout string `json:"fail_timeout,omitempty"`
	SlowStart   string `json:"slow_start,omitempty"`
	Backup      *bool  `json:"backup,omitempty"`
	Down        *bool  `json:"down,omitempty"`
	Weight      *int   `json:"weight,omitempty"`
	Service     string `json:"service,omitempty"`
}
type apiErrorResponse struct {
	Error     apiError
	RequestID string `json:"request_id"`
	Href      string
}
func (resp *apiErrorResponse) toString() string {
	return fmt.Sprintf("error.status=%v; error.text=%v; error.code=%v; request_id=%v; href=%v",
		resp.Error.Status, resp.Error.Text, resp.Error.Code, resp.RequestID, resp.Href)
}
type apiError struct {
	Status int
	Text   string
	Code   string
}
type internalError struct {
	apiError
	err string
}
func (internalError *internalError) Error() string {
	return internalError.err
}
func (internalError *internalError) Wrap(err string) *internalError {
	internalError.err = fmt.Sprintf("%v. %v", err, internalError.err)
	return internalError
}
type Stats struct {
	NginxInfo         NginxInfo
	Caches            Caches
	Processes         Processes
	Connections       Connections
	Slabs             Slabs
	HTTPRequests      HTTPRequests
	SSL               SSL
	ServerZones       ServerZones
	Upstreams         Upstreams
	StreamServerZones StreamServerZones
	StreamUpstreams   StreamUpstreams
	StreamZoneSync    *StreamZoneSync
	LocationZones     LocationZones
	Resolvers         Resolvers
}
type NginxInfo struct {
	Version         string
	Build           string
	Address         string
	Generation      uint64
	LoadTimestamp   string `json:"load_timestamp"`
	Timestamp       string
	ProcessID       uint64 `json:"pid"`
	ParentProcessID uint64 `json:"ppid"`
}
type Caches = map[string]HTTPCache
type HTTPCache struct {
	Size        uint64
	MaxSize     uint64 `json:"max_size"`
	Cold        bool
	Hit         CacheStats
	Stale       CacheStats
	Updating    CacheStats
	Revalidated CacheStats
	Miss        CacheStats
	Expired     ExtendedCacheStats
	Bypass      ExtendedCacheStats
}
type CacheStats struct {
	Responses uint64
	Bytes     uint64
}
type ExtendedCacheStats struct {
	CacheStats
	ResponsesWritten uint64 `json:"responses_written"`
	BytesWritten     uint64 `json:"bytes_written"`
}
type Connections struct {
	Accepted uint64
	Dropped  uint64
	Active   uint64
	Idle     uint64
}
type Slabs map[string]Slab
type Slab struct {
	Pages Pages
	Slots Slots
}
type Pages struct {
	Used uint64
	Free uint64
}
type Slots map[string]Slot
type Slot struct {
	Used  uint64
	Free  uint64
	Reqs  uint64
	Fails uint64
}
type HTTPRequests struct {
	Total   uint64
	Current uint64
}
type SSL struct {
	Handshakes       uint64
	HandshakesFailed uint64 `json:"handshakes_failed"`
	SessionReuses    uint64 `json:"session_reuses"`
}
type ServerZones map[string]ServerZone
type ServerZone struct {
	Processing uint64
	Requests   uint64
	Responses  Responses
	Discarded  uint64
	Received   uint64
	Sent       uint64
}
type StreamServerZones map[string]StreamServerZone
type StreamServerZone struct {
	Processing  uint64
	Connections uint64
	Sessions    Sessions
	Discarded   uint64
	Received    uint64
	Sent        uint64
}
type StreamZoneSync struct {
	Zones  map[string]SyncZone
	Status StreamZoneSyncStatus
}
type SyncZone struct {
	RecordsPending uint64 `json:"records_pending"`
	RecordsTotal   uint64 `json:"records_total"`
}
type StreamZoneSyncStatus struct {
	BytesIn     uint64 `json:"bytes_in"`
	MsgsIn      uint64 `json:"msgs_in"`
	MsgsOut     uint64 `json:"msgs_out"`
	BytesOut    uint64 `json:"bytes_out"`
	NodesOnline uint64 `json:"nodes_online"`
}
type Responses struct {
	Responses1xx uint64 `json:"1xx"`
	Responses2xx uint64 `json:"2xx"`
	Responses3xx uint64 `json:"3xx"`
	Responses4xx uint64 `json:"4xx"`
	Responses5xx uint64 `json:"5xx"`
	Total        uint64
}
type Sessions struct {
	Sessions2xx uint64 `json:"2xx"`
	Sessions4xx uint64 `json:"4xx"`
	Sessions5xx uint64 `json:"5xx"`
	Total       uint64
}
type Upstreams map[string]Upstream
type Upstream struct {
	Peers      []Peer
	Keepalives int
	Zombies    int
	Zone       string
	Queue      Queue
}
type StreamUpstreams map[string]StreamUpstream
type StreamUpstream struct {
	Peers   []StreamPeer
	Zombies int
	Zone    string
}
type Queue struct {
	Size      int
	MaxSize   int `json:"max_size"`
	Overflows uint64
}
type Peer struct {
	ID           int
	Server       string
	Service      string
	Name         string
	Backup       bool
	Weight       int
	State        string
	Active       uint64
	MaxConns     int `json:"max_conns"`
	Requests     uint64
	Responses    Responses
	Sent         uint64
	Received     uint64
	Fails        uint64
	Unavail      uint64
	HealthChecks HealthChecks `json:"health_checks"`
	Downtime     uint64
	Downstart    string
	Selected     string
	HeaderTime   uint64 `json:"header_time"`
	ResponseTime uint64 `json:"response_time"`
}
type StreamPeer struct {
	ID            int
	Server        string
	Service       string
	Name          string
	Backup        bool
	Weight        int
	State         string
	Active        uint64
	MaxConns      int `json:"max_conns"`
	Connections   uint64
	ConnectTime   int    `json:"connect_time"`
	FirstByteTime int    `json:"first_byte_time"`
	ResponseTime  uint64 `json:"response_time"`
	Sent          uint64
	Received      uint64
	Fails         uint64
	Unavail       uint64
	HealthChecks  HealthChecks `json:"health_checks"`
	Downtime      uint64
	Downstart     string
	Selected      string
}
type HealthChecks struct {
	Checks     uint64
	Fails      uint64
	Unhealthy  uint64
	LastPassed bool `json:"last_passed"`
}
type LocationZones map[string]LocationZone
type Resolvers map[string]Resolver
type LocationZone struct {
	Requests  int64
	Responses Responses
	Discarded int64
	Received  int64
	Sent      int64
}
type Resolver struct {
	Requests  ResolverRequests  `json:"requests"`
	Responses ResolverResponses `json:"responses"`
}
type ResolverRequests struct {
	Name int64
	Srv  int64
	Addr int64
}
type ResolverResponses struct {
	Noerror  int64
	Formerr  int64
	Servfail int64
	Nxdomain int64
	Notimp   int64
	Refused  int64
	Timedout int64
	Unknown  int64
}
type Processes struct {
	Respawned int64
}
func NewNginxClient(httpClient *http.Client, apiEndpoint string) (*NginxClient, error) {
	return NewNginxClientWithVersion(httpClient, apiEndpoint, APIVersion)
}
func NewNginxClientWithVersion(httpClient *http.Client, apiEndpoint string, version int) (*NginxClient, error) {
	if !versionSupported(version) {
		return nil, fmt.Errorf("API version %v is not supported by the client", version)
	}
	versions, err := getAPIVersions(httpClient, apiEndpoint)
	if err != nil {
		return nil, fmt.Errorf("error accessing the API: %w", err)
	}
	found := false
	for _, v := range *versions {
		if v == version {
			found = true
			break
		}
	}
	if !found {
		return nil, ErrUnsupportedVer
	}
	return &NginxClient{
		apiEndpoint: apiEndpoint,
		httpClient:  httpClient,
		version:     version,
	}, nil
}
func versionSupported(n int) bool {
	for _, version := range supportedAPIVersions {
		if n == version {
			return true
		}
	}
	return false
}
func getAPIVersions(httpClient *http.Client, endpoint string) (*versions, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to create a get request: %w", err)
	}
	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("%v is not accessible: %w", endpoint, err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("%v is not accessible: expected %v response, got %v", endpoint, http.StatusOK, resp.StatusCode)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("error while reading body of the response: %w", err)
	}
	var vers versions
	err = json.Unmarshal(body, &vers)
	if err != nil {
		return nil, fmt.Errorf("error unmarshalling versions, got %q response: %w", string(body), err)
	}
	return &vers, nil
}
func createResponseMismatchError(respBody io.ReadCloser) *internalError {
	apiErrResp, err := readAPIErrorResponse(respBody)
	if err != nil {
		return &internalError{
			err: fmt.Sprintf("failed to read the response body: %v", err),
		}
	}
	return &internalError{
		err:      apiErrResp.toString(),
		apiError: apiErrResp.Error,
	}
}
func readAPIErrorResponse(respBody io.ReadCloser) (*apiErrorResponse, error) {
	body, err := ioutil.ReadAll(respBody)
	if err != nil {
		return nil, fmt.Errorf("failed to read the response body: %w", err)
	}
	var apiErr apiErrorResponse
	err = json.Unmarshal(body, &apiErr)
	if err != nil {
		return nil, fmt.Errorf("error unmarshalling apiErrorResponse: got %q response: %w", string(body), err)
	}
	return &apiErr, nil
}
func (client *NginxClient) CheckIfUpstreamExists(upstream string) error {
	_, err := client.GetHTTPServers(upstream)
	return err
}
func (client *NginxClient) GetHTTPServers(upstream string) ([]UpstreamServer, error) {
	path := fmt.Sprintf("http/upstreams/%v/servers", upstream)
	var servers []UpstreamServer
	err := client.get(path, &servers)
	if err != nil {
		return nil, fmt.Errorf("failed to get the HTTP servers of upstream %v: %w", upstream, err)
	}
	return servers, nil
}
func (client *NginxClient) AddHTTPServer(upstream string, server UpstreamServer) error {
	id, err := client.getIDOfHTTPServer(upstream, server.Server)
	if err != nil {
		return fmt.Errorf("failed to add %v server to %v upstream: %w", server.Server, upstream, err)
	}
	if id != -1 {
		return fmt.Errorf("failed to add %v server to %v upstream: server already exists", server.Server, upstream)
	}
	path := fmt.Sprintf("http/upstreams/%v/servers/", upstream)
	err = client.post(path, &server)
	if err != nil {
		return fmt.Errorf("failed to add %v server to %v upstream: %w", server.Server, upstream, err)
	}
	return nil
}