http_client

package
v0.0.12 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2023 License: MIT Imports: 17 Imported by: 0

README

jamf_api_negotiation.go.

The file jamf_api_negotiation.go handles the content type negotiation and response decoding for different types of JAMF APIs.

Constants and Types:

ContentType: A type alias for a string that represents the content type. JSON and XML: Constants representing the "application/json" and "application/xml" content types, respectively. Functions:

determineAPIType: Determines the type of API (Classic or JamfPro) based on the endpoint string. It logs a warning if it's unable to determine the API type and defaults to "Unknown". DetermineContentType: Determines the content type (JSON or XML) based on the API type and the HTTP method. By default, it returns JSON. UnmarshalResponse: Decodes the response body based on the JAMF API type and the HTTP method. It can handle both JSON and XML responses depending on the API type and method. Now, I'll move on to the next file, http_request.go, to understand its contents and how it relates to the issue you mentioned.

http_request.go

The file http_request.go handles the construction and execution of HTTP requests.

Comments:

constructRequest: This function determines the API type and content type based on the endpoint and method, marshals the request body to the appropriate format (JSON or XML) based on the content type, and sends the HTTP request. doRequest: This function calls constructRequest to send the HTTP request, uses UnmarshalResponse to decode the response into the desired format based on the API type and method, and handles the decision for retries based on the response status code. doRequestWithRetry: This function retries the request if a rate limit error is encountered and implements a backoff strategy to avoid overloading the API server. Functions:

constructRequest: Constructs and sends an HTTP request. It first determines the API type and content type, then marshals the request body based on the content type, and finally constructs and sends the HTTP request. The snippet provided seems to be truncated, and I haven't yet seen the implementations of doRequest and doRequestWithRetry.

Functions (Continued from constructRequest): constructRequest (continued): After constructing the HTTP request, the function adds necessary headers, including the authorization token. If the token is invalid, it attempts to refresh it. It then sends the request and logs any errors.

DoRequest: This function sends an HTTP request and handles retries if necessary.

Starts by logging the initiation of the request if in DebugMode. Checks the HTTP method to decide if it should use retries or send the request directly. Some methods (POST and PUT) are set to send directly without retries. Calls constructRequest to send the actual request. Uses UnmarshalResponse to decode the response based on the API type and HTTP method. If the HTTP method is in the directMethods map or if the response status code indicates success (200-299 range), it returns the response. Otherwise, it seems to indicate that the request might need to be retried, but the logic is truncated. From the provided portion, I see that the DoRequest method returns the response and any error that occurs during the request. This function seems to be the one called in the ssoFailover.go file, which you mentioned earlier.

http_methods.go

The http_methods.go file provides convenient methods for making various HTTP requests (GET, POST, PUT, DELETE) using the Client type. Here's a brief overview:

Methods: Get: Sends a GET request to the specified endpoint and unmarshals the response into the provided out variable. The caller is responsible for closing the response body. Post: Sends a POST request to the specified endpoint with the provided body and unmarshals the response into the out variable. Put: Sends a PUT request to the specified endpoint with the provided body and unmarshals the response into the out variable. Delete: Sends a DELETE request to the specified endpoint and unmarshals the response into the out variable. (The implementation seems to be truncated in the provided snippet.) Each of these methods logs the request details if the client is in DebugMode. They all use the DoRequest method from the http_request.go file to actually send the request and handle the response.

With this understanding, I'll proceed to the next file, http_logging.go, to further understand the client's behavior and functionalities.

http_logging.go

The http_logging.go file is focused on logging functionalities. Here's a breakdown:

Logger Interface:

Logger is an interface that defines methods for different logging levels: Trace, Debug, Info, Warn, Error, and Fatal. Default Logger:

defaultLogger is a struct that implements the Logger interface using Go's standard log package. Each method (e.g., Trace, Debug, Info, etc.) logs messages with corresponding prefixes like "[TRACE]", "[DEBUG]", etc. The Fatal method logs the message and then calls log.Fatalln, which will exit the program. Function:

NewDefaultLogger: This function returns a new instance of the default logger. This file provides a standardized way to handle logging throughout the client's codebase. The use of an interface (Logger) allows for flexibility in terms of using other logging libraries or custom logging mechanisms if needed.

http_helpers.go

The http_helpers.go file contains utility functions to assist with HTTP operations. Here's a summary:

Functions: ParseISO8601Date: Tries to parse a string date in ISO 8601 format using the RFC3339 format. It returns a time.Time object and an error.

EnsureHTTPScheme: Ensures that a given URL string is prefixed with either "http://" or "https://". If neither prefix is present, it defaults to adding "http://".

These helper functions are used throughout the client code to handle specific tasks related to HTTP operations and data manipulation.

http_error_handling.go

The http_error_handling.go file seems to focus on handling API errors and converting them into structured errors when possible. Here's a summary:

Types:

APIError: Represents a structured API error response with fields for status code and an error message. Methods & Functions:

handleAPIError: Handles error responses from the API and tries to convert them into a structured error. If the error response from the API is structured (contains an error message and code), it logs and returns a structured APIError. If the error response isn't structured, it tries to decode the error message directly from the response body. If this also fails, it defaults to using the HTTP status message as the error message.

Error: This method on the APIError type returns a string representation of the error, combining the status code and the error message.

translateStatusCode: Provides human-readable messages for various HTTP status codes. It uses a map to match status codes to their corresponding messages.

Given the focus on error handling in this file, it provides context on how the client processes and presents API errors to the user or caller.

http_client.go

The http_client.go file provides core functionalities and structures related to the HTTP client's behavior. Methods:

NewClient: Creates a new instance of the Client. If no logger is provided, it defaults to the defaultLogger. It applies any additional options provided to it. SetAuthMethod: Sets the authentication method for the client. Supported methods are "bearer" and "oauth". constructAPIEndpoint: Constructs the full URL for a given API endpoint path. ObtainToken: Fetches and sets an authentication token using the provided username and password. The method constructs the authentication URL, sends a POST request with basic authentication, handles potential deprecation warnings, checks the response status, and then decodes the token from the response. If successful, it sets the token and expiry time on the client. Error Handling:

In the ObtainToken method, if the response status code isn't http.StatusOK, it logs a warning and invokes c.handleAPIError(resp) to handle the error.

http_client_auth.go

The http_client_auth.go file focuses on authentication functionalities, particularly around handling OAuth tokens. Here's a summary:

Types:

ClientAuthConfig: Represents the structure to read authentication details from a JSON configuration file. It includes fields for BaseURL, Username, Password, ClientID, and ClientSecret. OAuthResponse: Represents the response structure when obtaining an OAuth access token. Fields include AccessToken, ExpiresIn, TokenType, RefreshToken, and Error. OAuthCredentials: Contains the client ID and client secret required for OAuth authentication. Functions & Methods:

LoadClientAuthConfig: Reads a JSON configuration file and decodes it into a ClientAuthConfig struct. It retrieves authentication details like BaseURL, Username, and Password for the client. SetOAuthCredentials: Sets the OAuth credentials (Client ID and Client Secret) for the client instance. These credentials are used for obtaining and refreshing OAuth tokens for authentication. ObtainOAuthToken: Fetches an OAuth access token using the provided OAuthCredentials (Client ID and Client Secret). The file provides functionalities for loading authentication configurations, setting OAuth credentials, and obtaining OAuth tokens, which are crucial for interacting with protected endpoints.

Documentation

Overview

http_client.go

The `http_client` package provides a configurable HTTP client tailored for interacting with specific APIs.

It supports different authentication methods, including "bearer" and "oauth". The client is designed with a focus on concurrency management, structured error handling, and flexible configuration options. The package offers a default timeout, custom backoff strategies, dynamic rate limiting, and detailed logging capabilities. The main `Client` structure encapsulates all necessary components, like the baseURL, authentication details, and an embedded standard HTTP client.

http_client_bearer_token_auth.go

The http_client_auth package focuses on authentication mechanisms for an HTTP client.

It provides structures and methods for handling both basic and bearer token based authentication

http_client_oauth.go

The http_client_auth package focuses on authentication mechanisms for an HTTP client.

It provides structures and methods for handling OAuth-based authentication

http_concurrency_management.go Package http_client provides utilities to manage HTTP client interactions, including concurrency control. The Concurrency Manager ensures no more than a certain number of concurrent requests (e.g., 5 for Jamf Pro) are sent at the same time. This is managed using a semaphore

http_error_handling.go This package provides utility functions and structures for handling and categorizing HTTP error responses.

http_helpers.go

http_logging.go

http_methods.go

http_token_management.go

jamfpro_api_handler.go

------------------------------Summary----------------------------------------

This is a api handler module for the http_client to accommodate specifics of jamf's api(s). It handles the encoding (marshalling) and decoding (unmarshalling) of data. It also sets the correct content headers for the various http methods.

This module integrates with the http_client logger for wrapped error handling for human readable return codes. It also supports the http_clients debugMode for verbose logging.

The logic of this module is defined as follows: Classic API:

For requests (GET, POST, PUT, DELETE): - Encoding (Marshalling): Use XML format. For responses (GET, POST, PUT): - Decoding (Unmarshalling): Use XML format. For responses (DELETE): - Handle response codes as response body lacks anything useful. Headers - Set content header as application/xml

JamfPro API:

For requests (GET, POST, PUT, DELETE): - Encoding (Marshalling): Use JSON format. For responses (GET, POST, PUT): - Decoding (Unmarshalling): Use JSON format. For responses (DELETE): - Handle response codes as response body lacks anything useful. Headers - Set content header as application/xml

sdk_version.go

Index

Constants

View Source
const (
	SDKVersion    = "10.50.0"
	UserAgentBase = "go-jamfpro-api-sdk"
)
View Source
const DefaultTimeout = 10 * time.Second

Variables

This section is empty.

Functions

func CheckDeprecationHeader

func CheckDeprecationHeader(resp *http.Response, logger Logger)

CheckDeprecationHeader checks the response headers for the Deprecation header and logs a warning if present.

func EnsureHTTPScheme

func EnsureHTTPScheme(url string) string

EnsureHTTPScheme prefixes a URL with "http://" it defaults to "https://" doesn't already have an "https://".

func GetUserAgent

func GetUserAgent() string

func ParseISO8601Date

func ParseISO8601Date(dateStr string) (time.Time, error)

ParseISO8601Date attempts to parse a string date in ISO 8601 format.

Types

type APIError

type APIError struct {
	StatusCode int
	Message    string
}

APIError represents a structured API error response.

func (*APIError) Error

func (e *APIError) Error() string

Error returns a string representation of the APIError.

type APIHandler

type APIHandler interface {
	MarshalRequest(body interface{}, method string) ([]byte, error)
	UnmarshalResponse(resp *http.Response, out interface{}) error
	GetContentType(method string) string
	SetLogger(logger Logger)
	SetDebugMode(debug bool)
}

APIHandler is an interface for encoding, decoding, and determining content types for different API implementations. It encapsulates behavior for encoding and decoding requests and responses.

func GetAPIHandler

func GetAPIHandler(endpoint string, debugMode bool) APIHandler

GetAPIHandler determines the appropriate APIHandler based on the endpoint. It identifies the type of API (Classic, JamfPro, or Unknown) and returns the corresponding handler.

type BearerTokenAuthCredentials

type BearerTokenAuthCredentials struct {
	Username string
	Password string
}

BearerTokenAuthCredentials represents the username and password for basic authentication.

type ClassicApiHandler

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

ClassicApiHandler handles the specifics of the Classic API.

func (*ClassicApiHandler) GetContentType

func (h *ClassicApiHandler) GetContentType(method string) string

GetContentType for ClassicApiHandler always returns XML as the content type.

func (*ClassicApiHandler) MarshalRequest

func (h *ClassicApiHandler) MarshalRequest(body interface{}, method string) ([]byte, error)

MarshalRequest encodes the request body in XML format for the Classic API.

func (*ClassicApiHandler) SetDebugMode

func (h *ClassicApiHandler) SetDebugMode(debug bool)

func (*ClassicApiHandler) SetLogger

func (h *ClassicApiHandler) SetLogger(logger Logger)

SetLogger assigns a logger instance to the ClassicApiHandler.

func (*ClassicApiHandler) UnmarshalResponse

func (h *ClassicApiHandler) UnmarshalResponse(resp *http.Response, out interface{}) error

UnmarshalResponse decodes the response body from XML format for the Classic API.

type Client

type Client struct {
	BaseURL string

	Token string

	Expiry time.Time

	ConcurrencyMgr *ConcurrencyManager
	// contains filtered or unexported fields
}

Client represents an HTTP client to interact with a specific API.

func NewClient

func NewClient(baseURL string, config Config, logger Logger, options ...ClientOption) *Client

NewClient initializes a new http client instance with the given baseURL, logger, concurrency manager and client configuration

If TokenLifespan and BufferPeriod aren't set in the config, they default to 30 minutes and 5 minutes, respectively. If TotalRetryDuration isn't set in the config, it defaults to 1 minute. If no logger is provided, a default logger will be used. Any additional options provided will be applied to the client during initialization. Detect authentication method based on supplied credential type

func (*Client) Delete

func (c *Client) Delete(endpoint string, out interface{}) (*http.Response, error)

Delete sends a DELETE request to the specified endpoint and unmarshals the response into 'out'. The caller is responsible for closing the response body.

func (*Client) DoRequest

func (c *Client) DoRequest(method, endpoint string, body, out interface{}) (*http.Response, error)

func (*Client) Get

func (c *Client) Get(endpoint string, out interface{}) (*http.Response, error)

Get sends a GET request to the specified endpoint and unmarshals the response into 'out'. The caller is responsible for closing the response body.

func (*Client) InvalidateOAuthToken

func (c *Client) InvalidateOAuthToken() error

InvalidateOAuthToken invalidates the current OAuth access token. After invalidation, the token cannot be used for further API requests.

func (*Client) ObtainOAuthToken

func (c *Client) ObtainOAuthToken(credentials OAuthCredentials) error

ObtainOAuthToken fetches an OAuth access token using the provided OAuthCredentials (Client ID and Client Secret). It updates the client's Token and Expiry fields with the obtained values.

func (*Client) ObtainToken

func (c *Client) ObtainToken() error

ObtainToken fetches and sets an authentication token using the stored basic authentication credentials.

func (*Client) Patch

func (c *Client) Patch(endpoint string, body, out interface{}) (*http.Response, error)

Patch sends a PATCH request to the specified endpoint with the provided body and unmarshals the response into 'out'. The caller is responsible for closing the response body.

func (*Client) Post

func (c *Client) Post(endpoint string, body, out interface{}) (*http.Response, error)

Post sends a POST request to the specified endpoint with the provided body and unmarshals the response into 'out'. The caller is responsible for closing the response body.

func (*Client) Put

func (c *Client) Put(endpoint string, body, out interface{}) (*http.Response, error)

Put sends a PUT request to the specified endpoint with the provided body and unmarshals the response into 'out'. The caller is responsible for closing the response body.

func (*Client) RefreshOAuthToken

func (c *Client) RefreshOAuthToken() error

RefreshOAuthToken refreshes the current OAuth token.

func (*Client) RefreshToken

func (c *Client) RefreshToken() error

RefreshToken refreshes the current authentication token.

func (*Client) SetBearerTokenAuthCredentials

func (c *Client) SetBearerTokenAuthCredentials(credentials BearerTokenAuthCredentials)

SetBearerTokenAuthCredentials sets the BearerTokenAuthCredentials (Username and Password) for the client instance. These credentials are used for obtaining and refreshing bearer tokens for authentication.

func (*Client) SetOAuthCredentials

func (c *Client) SetOAuthCredentials(credentials OAuthCredentials)

SetOAuthCredentials sets the OAuth credentials (Client ID and Client Secret) for the client instance. These credentials are used for obtaining and refreshing OAuth tokens for authentication.

func (*Client) ValidAuthTokenCheck

func (c *Client) ValidAuthTokenCheck() bool

ValidAuthToken checks if the current token is valid and not close to expiry. If the token is invalid, it tries to refresh it.

type ClientAuthConfig

type ClientAuthConfig struct {
	BaseURL      string `json:"baseURL,omitempty"`
	Username     string `json:"username,omitempty"`
	Password     string `json:"password,omitempty"`
	ClientID     string `json:"clientID,omitempty"`
	ClientSecret string `json:"clientSecret,omitempty"`
}

ClientAuthConfig represents the structure to read authentication details from a JSON configuration file.

func LoadClientAuthConfig

func LoadClientAuthConfig(filename string) (*ClientAuthConfig, error)

LoadClientAuthConfig reads a JSON configuration file and decodes it into a ClientAuthConfig struct. It is used to retrieve authentication details like BaseURL, Username, and Password for the client.

type ClientOption

type ClientOption func(*Client)

ClientOption defines a function type for modifying client properties during initialization.

type ConcurrencyManager

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

ConcurrencyManager controls the number of concurrent HTTP requests.

func NewConcurrencyManager

func NewConcurrencyManager(limit int, logger Logger, debugMode bool) *ConcurrencyManager

NewConcurrencyManager initializes a new ConcurrencyManager with the given limit.

func (*ConcurrencyManager) Acquire

func (c *ConcurrencyManager) Acquire(ctx context.Context) (uuid.UUID, error)

Acquire blocks until a token is available to proceed, or until the context is done.

func (*ConcurrencyManager) Release

func (c *ConcurrencyManager) Release(requestID uuid.UUID)

Release releases a token, allowing another request to proceed.

type Config

type Config struct {
	DebugMode                 bool
	MaxRetryAttempts          int
	CustomBackoff             func(attempt int) time.Duration
	EnableDynamicRateLimiting bool
	Logger                    Logger
	MaxConcurrentRequests     int
	TokenLifespan             time.Duration
	BufferPeriod              time.Duration
	TotalRetryDuration        time.Duration
}

Config holds configuration options for the HTTP Client.

type JamfProApiHandler

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

JamfProApiHandler handles the specifics of the JamfPro API.

func (*JamfProApiHandler) GetContentType

func (h *JamfProApiHandler) GetContentType(method string) string

GetContentType for JamfProApiHandler always returns JSON as the content type.

func (*JamfProApiHandler) MarshalRequest

func (h *JamfProApiHandler) MarshalRequest(body interface{}, method string) ([]byte, error)

MarshalRequest encodes the request body in JSON format for the JamfPro API.

func (*JamfProApiHandler) SetDebugMode

func (h *JamfProApiHandler) SetDebugMode(debug bool)

func (*JamfProApiHandler) SetLogger

func (h *JamfProApiHandler) SetLogger(logger Logger)

SetLogger assigns a logger instance to the JamfProApiHandler.

func (*JamfProApiHandler) UnmarshalResponse

func (h *JamfProApiHandler) UnmarshalResponse(resp *http.Response, out interface{}) error

UnmarshalResponse decodes the response body from JSON format for the JamfPro API.

type Logger

type Logger interface {
	Trace(msg string, keysAndValues ...interface{}) // For very detailed logs
	Debug(msg string, keysAndValues ...interface{}) // For development and troubleshooting
	Info(msg string, keysAndValues ...interface{})  // Informational messages
	Warn(msg string, keysAndValues ...interface{})  // For potentially problematic situations
	Error(msg string, keysAndValues ...interface{}) // For errors that might still allow the app to continue running
	Fatal(msg string, keysAndValues ...interface{}) // For errors that might prevent the app from continuing
}

Logger is an interface for logging within the SDK.

func NewDefaultLogger

func NewDefaultLogger() Logger

NewDefaultLogger returns a new instance of the default logger.

type OAuthCredentials

type OAuthCredentials struct {
	ClientID     string
	ClientSecret string
}

OAuthCredentials contains the client ID and client secret required for OAuth authentication.

type OAuthResponse

type OAuthResponse struct {
	AccessToken  string `json:"access_token"`
	ExpiresIn    int64  `json:"expires_in"`
	TokenType    string `json:"token_type"`
	RefreshToken string `json:"refresh_token,omitempty"`
	Error        string `json:"error,omitempty"`
}

OAuthResponse represents the response structure when obtaining an OAuth access token.

type StructuredError

type StructuredError struct {
	Error struct {
		Code    string `json:"code"`
		Message string `json:"message"`
	} `json:"error"`
}

StructuredError represents a structured error response from the API.

type TokenResponse

type TokenResponse struct {
	Token   string    `json:"token"`
	Expires time.Time `json:"expires"`
}

TokenResponse represents the structure of a token response from the API.

type UnknownApiHandler

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

UnknownApiHandler provides default behavior for unrecognized API types.

func (*UnknownApiHandler) GetContentType

func (h *UnknownApiHandler) GetContentType(method string) string

func (*UnknownApiHandler) MarshalRequest

func (h *UnknownApiHandler) MarshalRequest(body interface{}, method string) ([]byte, error)

MarshalRequest returns an error since the API type is unsupported.

func (*UnknownApiHandler) SetDebugMode

func (h *UnknownApiHandler) SetDebugMode(debug bool)

func (*UnknownApiHandler) SetLogger

func (h *UnknownApiHandler) SetLogger(logger Logger)

SetLogger assigns a logger instance to the UnknownApiHandler.

func (*UnknownApiHandler) UnmarshalResponse

func (h *UnknownApiHandler) UnmarshalResponse(resp *http.Response, out interface{}) error

UnmarshalResponse returns an error since the API type is unsupported.

Jump to

Keyboard shortcuts

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