exclusivenetworks

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 18, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

README

exclusivenetworks

Go client library for the Exclusive Networks AccessNow GraphQL API.

Installation

go get github.com/enthus-golang/exclusivenetworks

Usage

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/enthus-golang/exclusivenetworks"
)

func main() {
	client := exclusivenetworks.New(
		"https://YOUR_GRAPHQL_BASE_URL",
		"https://YOUR_OAUTH_TOKEN_URL",
		"YOUR_CLIENT_ID",
		"YOUR_CLIENT_SECRET",
		"YOUR_SCOPE",
	)

	quote, err := client.GetQuoteByNumber(context.Background(), "QPL010006170")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("quote %s version %d\n", quote.QuoteNumber, quote.Version)

	for _, line := range quote.Lines {
		fmt.Printf("  %s %s — %s..%s\n",
			line.VendorPartNumber,
			line.SerialNumberSupported,
			line.ContractStartDate.Format("2006-01-02"),
			line.ContractEndDate.Format("2006-01-02"),
		)
	}
}

Options

client := exclusivenetworks.New(baseURL, tokenURL, clientID, clientSecret, scope,
	exclusivenetworks.WithHTTPClient(myHTTPClient),
	exclusivenetworks.WithRateLimit(60, 3600),               // per minute, per hour (0 = unlimited)
	exclusivenetworks.WithRetry(3, 500*time.Millisecond),    // max attempts, base backoff
)

License

Apache License 2.0

Documentation

Overview

Package exclusivenetworks is a Go client library for the Exclusive Networks AccessNow GraphQL API.

The API is authenticated via OAuth 2.0 client_credentials: a client ID, secret, and scope are exchanged at the token endpoint for a short-lived bearer token. The client caches the token internally and refreshes it proactively before expiry.

All public methods accept a context.Context for cancellation and timeout control. Non-2xx HTTP responses and GraphQL errors surface as typed errors that wrap the upstream status code, body, and (for GraphQL) the error envelope.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrQuoteNotFound is returned by GetQuoteByNumber when the search
	// yields no quote (or no latest-version quote) for the requested
	// quote number.
	ErrQuoteNotFound = errors.New("exclusivenetworks: quote not found")

	// ErrAmbiguousQuoteNumber is returned by GetQuoteByNumber when the
	// search yields more than one row with IsLatestVersion == true for
	// the same quoteNumber. This indicates upstream data inconsistency.
	ErrAmbiguousQuoteNumber = errors.New("exclusivenetworks: ambiguous quote number")

	// ErrUnauthorized matches HTTP 401/403 responses via errors.Is.
	ErrUnauthorized = errors.New("exclusivenetworks: unauthorized")

	// ErrNotFound matches HTTP 404 responses via errors.Is.
	ErrNotFound = errors.New("exclusivenetworks: not found")
)

Sentinel errors. Match with errors.Is.

Functions

This section is empty.

Types

type APIError

type APIError struct {
	StatusCode int
	Body       string
}

APIError carries the HTTP status code and raw response body for an unsuccessful HTTP-level API call.

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) Is

func (e *APIError) Is(target error) bool

Is allows callers to match ErrUnauthorized / ErrNotFound via errors.Is.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is an Exclusive Networks AccessNow GraphQL API client. It is safe for concurrent use by multiple goroutines.

func New

func New(baseURL, tokenURL, clientID, clientSecret, scope string, opts ...Option) *Client

New creates an Exclusive Networks AccessNow API client.

baseURL is the GraphQL endpoint. tokenURL is the OAuth2 token endpoint that issues client_credentials tokens. clientID, clientSecret, and scope are the OAuth2 credentials provisioned by Exclusive Networks. All four URLs/credentials are issued by Exclusive Networks on approval.

All five arguments are required; this constructor does not validate them — instead, the first call needing them surfaces any errors.

func (*Client) GetQuoteByNumber

func (c *Client) GetQuoteByNumber(ctx context.Context, quoteNumber string) (*Quote, error)

GetQuoteByNumber resolves a sales quote by its quoteNumber.

The upstream API can return multiple rows when a quote has been versioned (only IsLatestVersion == true is convertible to an order upstream). This method returns the latest-version row.

Returns ErrQuoteNotFound if no row matches or no matching row has IsLatestVersion == true, and ErrAmbiguousQuoteNumber if more than one IsLatestVersion == true row exists for the same quoteNumber.

type Date

type Date struct {
	time.Time
}

Date is a calendar date as it appears on AccessNow quote lines. It wraps time.Time and parses AccessNow's "YYYY-MM-DD" wire format.

JSON methods are defined directly on Date because the embedded time.Time's MarshalJSON/UnmarshalJSON expect RFC3339 — leaving them promoted would silently break round-tripping with AccessNow's date-only format.

func (Date) MarshalJSON

func (d Date) MarshalJSON() ([]byte, error)

MarshalJSON emits AccessNow's "YYYY-MM-DD" wire format. A zero Date emits the empty string so it round-trips cleanly with UnmarshalJSON.

func (*Date) UnmarshalJSON

func (d *Date) UnmarshalJSON(data []byte) error

UnmarshalJSON parses AccessNow's "YYYY-MM-DD" wire format. Empty string and JSON null both decode to a zero Date.

type GraphQLError

type GraphQLError struct {
	Message    string         `json:"message"`
	Path       []any          `json:"path,omitempty"`
	Extensions map[string]any `json:"extensions,omitempty"`
}

GraphQLError is a single entry from a GraphQL response's "errors" array.

type GraphQLErrors

type GraphQLErrors struct {
	Errors []GraphQLError
}

GraphQLErrors aggregates one or more GraphQL errors returned alongside a 200 OK response. The first message is surfaced for brevity; the rest are available via Errors.

func (*GraphQLErrors) Error

func (e *GraphQLErrors) Error() string

type Logger

type Logger interface {
	Printf(format string, args ...any)
}

Logger is the minimal logging interface accepted by WithLogger.

type Option

type Option func(*Client)

Option configures a Client.

func WithHTTPClient

func WithHTTPClient(httpClient *http.Client) Option

WithHTTPClient sets a custom HTTP client. The default is a new client with a 30s timeout. nil is ignored.

func WithLogger

func WithLogger(logger Logger) Option

WithLogger sets a logger for transient retry events. nil disables logging.

func WithRateLimit

func WithRateLimit(perMinute, perHour int) Option

WithRateLimit caps requests per minute and per hour. A non-positive value disables that limit. Both limits are evaluated; a request blocks (respecting context) when either bucket is empty.

func WithRetry

func WithRetry(maxAttempts int, baseBackoff time.Duration) Option

WithRetry configures retry behavior for transient failures (network errors, HTTP 5xx, HTTP 429). maxAttempts is the total number of attempts including the first; pass 1 to disable retries. baseBackoff is the initial delay between attempts; subsequent delays double up to a 30s cap with ±25% jitter. HTTP 429 honors the Retry-After header when present.

type Quote

type Quote struct {
	ID                     string      `json:"id"`
	QuoteNumber            string      `json:"quoteNumber"`
	Version                int         `json:"version"`
	IsLatestVersion        bool        `json:"isLatestVersion"`
	LastModifiedDateTime   string      `json:"lastModifiedDateTime"`
	Status                 string      `json:"status"`
	CustomerQuoteReference string      `json:"customerQuoteReference"`
	Vendor                 string      `json:"vendor"`
	ExpiryDate             Date        `json:"expiryDate"`
	DealType               string      `json:"dealType"`
	Lines                  []QuoteLine `json:"lines"`
}

Quote represents an Exclusive Networks sales quote.

Multiple versions of the same quoteNumber can exist; only the row with IsLatestVersion == true is convertible to a sales order upstream.

type QuoteLine

type QuoteLine struct {
	ID                    string  `json:"id"`
	SalesQuoteID          string  `json:"salesQuoteId"`
	LineSequenceNumber    int     `json:"lineSequenceNumber"`
	VendorID              string  `json:"vendorId"`
	Vendor                string  `json:"vendor"`
	ItemName              string  `json:"itemName"`
	Description           string  `json:"description"`
	Quantity              float64 `json:"quantity"`
	ItemType              string  `json:"itemType"`
	VendorPartNumber      string  `json:"vendorPartNumber"`
	SerialNumberSupported string  `json:"serialNumberSupported"`
	ContractStartDate     Date    `json:"contractStartDate"`
	ContractEndDate       Date    `json:"contractEndDate"`
	ManufactureID         string  `json:"manufactureId"`
	ManufactureName       string  `json:"manufactureName"`
	SubscriptionTerm      int     `json:"subscriptionTerm"`
	UnitPrice             float64 `json:"unitPrice"`
	Amount                float64 `json:"amount"`
	Currency              string  `json:"currency"`
}

QuoteLine represents a single line on a sales quote.

"Description" lines (per AccessNow §1.2.2) carry free-form text instead of a real item — they have ItemName == "Description" and VendorPartNumber == "Description". Callers that consume QuoteLine for asset/coverage purposes should skip these.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL