HTTP transport system with retry logic, host failover, request/response caching, and comprehensive error handling. Manages communication between clients and Algolia's API infrastructure.
Creates a comprehensive HTTP transport layer with retry logic, caching, and host management.
/**
* Creates an HTTP transporter with retry logic and caching
* @param options - Configuration for the transporter
* @returns Transporter instance for making HTTP requests
*/
function createTransporter(options: TransporterOptions): Transporter;
interface TransporterOptions {
/** Cache for host state management */
hostsCache: Cache;
/** Logger for transport events and debugging */
logger: Logger;
/** HTTP requester implementation */
requester: Requester;
/** Cache for in-flight requests */
requestsCache: Cache;
/** Cache for completed responses */
responsesCache: Cache;
/** Timeout configuration */
timeouts: Timeouts;
/** Available hosts for requests */
hosts: Host[];
/** Base headers for all requests */
baseHeaders: Headers;
/** Base query parameters for all requests */
baseQueryParameters: QueryParameters;
/** User agent for request identification */
algoliaAgent: AlgoliaAgent;
}
interface Transporter extends TransporterOptions {
/**
* Performs an HTTP request with retry logic and caching
* @param baseRequest - Request configuration
* @param baseRequestOptions - Optional request overrides
* @returns Promise resolving to the response
*/
request: <TResponse>(
baseRequest: Request,
baseRequestOptions?: RequestOptions
) => Promise<TResponse>;
}Usage Examples:
import {
createTransporter,
createMemoryCache,
createNullLogger,
createAuth,
createAlgoliaAgent
} from "@algolia/client-common";
// Create dependencies
const hostsCache = createMemoryCache();
const requestsCache = createMemoryCache();
const responsesCache = createMemoryCache();
const logger = createNullLogger();
const auth = createAuth("AppID", "APIKey");
const algoliaAgent = createAlgoliaAgent("5.35.0");
// Create transporter
const transporter = createTransporter({
hosts: [
{ url: "algolia.net", accept: "readWrite", protocol: "https" },
{ url: "algolia.com", accept: "readWrite", protocol: "https" }
],
hostsCache,
logger,
requester: myRequesterImplementation, // Must provide requester
requestsCache,
responsesCache,
timeouts: { connect: 2000, read: 5000, write: 30000 },
baseHeaders: auth.headers(),
baseQueryParameters: auth.queryParameters(),
algoliaAgent
});
// Make requests
const response = await transporter.request({
method: 'GET',
path: '/1/indexes',
queryParameters: {},
headers: {}
});Creates a host with state tracking for availability and timeout management.
/**
* Creates a stateful host with availability tracking
* @param host - Base host configuration
* @param status - Initial host status (default: 'up')
* @returns Stateful host with availability methods
*/
function createStatefulHost(
host: Host,
status?: StatefulHost['status']
): StatefulHost;
interface StatefulHost extends Host {
/** Current host status */
status: 'down' | 'timed out' | 'up';
/** Timestamp of last status update */
lastUpdate: number;
/** Check if host is available for requests */
isUp: () => boolean;
/** Check if host is in timeout state */
isTimedOut: () => boolean;
}Usage Examples:
import { createStatefulHost } from "@algolia/client-common";
const host = createStatefulHost({
url: "algolia.net",
accept: "readWrite",
protocol: "https"
});
console.log(host.isUp()); // true (initially up)
console.log(host.isTimedOut()); // false
// Host becomes available again after 2 minutes even if marked down
const downHost = createStatefulHost(
{ url: "algolia.com", accept: "read", protocol: "https" },
"down"
);
// Will return true after 2 minutes regardless of status
setTimeout(() => {
console.log(downHost.isUp()); // true after expiration delay
}, 2 * 60 * 1000 + 100);Host Configuration:
interface Host {
/** Host URL (without protocol) */
url: string;
/** Host capabilities */
accept: 'read' | 'readWrite' | 'write';
/** Protocol to use */
protocol: 'http' | 'https';
/** Optional port number */
port?: number;
}Request/Response Types:
interface Request {
/** HTTP method */
method: Method;
/** API path */
path: string;
/** Query parameters */
queryParameters: QueryParameters;
/** Request body data */
data?: Array<Record<string, any>> | Record<string, any>;
/** Request headers */
headers: Headers;
/** Whether response should be cached */
cacheable?: boolean;
/** Whether to use read transporter for POST requests */
useReadTransporter?: boolean;
}
interface Response {
/** Response body as string */
content: string;
/** Whether request timed out */
isTimedOut: boolean;
/** HTTP status code */
status: number;
}
interface EndRequest extends Pick<Request, 'headers' | 'method'> {
/** Full URL for the request */
url: string;
/** Connection timeout in milliseconds */
connectTimeout: number;
/** Response timeout in milliseconds */
responseTimeout: number;
/** Serialized request body */
data?: string;
}Request Options:
interface RequestOptions extends Pick<Request, 'cacheable'> {
/** Custom timeout overrides */
timeouts?: Partial<Timeouts>;
/** Additional headers for this request */
headers?: Headers;
/** Additional query parameters for this request */
queryParameters?: QueryParameters;
/** Additional data for this request */
data?: Array<Record<string, any>> | Record<string, any>;
}
interface Timeouts {
/** Connection timeout in milliseconds */
connect: number;
/** Read timeout in milliseconds */
read: number;
/** Write timeout in milliseconds */
write: number;
}Requester Interface:
interface Requester {
/**
* Sends an HTTP request
* @param request - Complete request configuration
* @returns Promise resolving to response
*/
send: (request: EndRequest) => Promise<Response>;
}URL Serialization:
/**
* Builds complete URL from host, path, and query parameters
* @param host - Host configuration
* @param path - API path
* @param queryParameters - Query parameters to append
* @returns Complete URL string
*/
function serializeUrl(host: Host, path: string, queryParameters: QueryParameters): string;
/**
* Serializes query parameters to URL query string
* @param parameters - Query parameters object
* @returns URL-encoded query string
*/
function serializeQueryParameters(parameters: QueryParameters): string;Data Serialization:
/**
* Serializes request data to JSON string
* @param request - Base request
* @param requestOptions - Request options with additional data
* @returns JSON string or undefined for GET requests
*/
function serializeData(request: Request, requestOptions: RequestOptions): string | undefined;
/**
* Merges and normalizes HTTP headers
* @param baseHeaders - Base headers
* @param requestHeaders - Request-specific headers
* @param requestOptionsHeaders - Options headers
* @returns Merged headers with normalized keys
*/
function serializeHeaders(
baseHeaders: Headers,
requestHeaders: Headers,
requestOptionsHeaders?: Headers
): Headers;Response Handling:
/**
* Deserializes successful response content
* @param response - HTTP response
* @returns Parsed response object
* @throws DeserializationError if JSON parsing fails
*/
function deserializeSuccess<TObject>(response: Response): TObject;
/**
* Creates appropriate error from failed response
* @param response - Failed HTTP response
* @param stackFrame - Request stack trace
* @returns Error instance (ApiError or DetailedApiError)
*/
function deserializeFailure(response: Response, stackFrame: StackFrame[]): Error;Response Classification:
/**
* Checks if response indicates network error
* @param response - Response to check (excluding content)
* @returns True if network error occurred
*/
function isNetworkError(response: Omit<Response, 'content'>): boolean;
/**
* Checks if response should trigger retry logic
* @param response - Response to check (excluding content)
* @returns True if request should be retried
*/
function isRetryable(response: Omit<Response, 'content'>): boolean;
/**
* Checks if response indicates success (2xx status)
* @param response - Response to check
* @returns True if response is successful
*/
function isSuccess(response: Pick<Response, 'status'>): boolean;Utility Functions:
/**
* Shuffles array elements randomly
* @param array - Array to shuffle
* @returns Shuffled array (modifies original)
*/
function shuffle<TData>(array: TData[]): TData[];Stack Frame Types:
interface StackFrame {
/** Request that was made */
request: EndRequest;
/** Response that was received */
response: Response;
/** Host that handled the request */
host: Host;
/** Number of retries remaining */
triesLeft: number;
}Credential Sanitization:
/**
* Removes credentials from stack trace for safe logging
* @param stackTrace - Stack trace with potential credentials
* @returns Sanitized stack trace
*/
function stackTraceWithoutCredentials(stackTrace: StackFrame[]): StackFrame[];
/**
* Removes credentials from single stack frame
* @param stackFrame - Stack frame with potential credentials
* @returns Sanitized stack frame
*/
function stackFrameWithoutCredentials(stackFrame: StackFrame): StackFrame;Custom Requester Implementation:
import { Requester, EndRequest, Response } from "@algolia/client-common";
class FetchRequester implements Requester {
async send(request: EndRequest): Promise<Response> {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), request.responseTimeout);
try {
const response = await fetch(request.url, {
method: request.method,
headers: request.headers,
body: request.data,
signal: controller.signal
});
clearTimeout(timeoutId);
return {
content: await response.text(),
status: response.status,
isTimedOut: false
};
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
return {
content: '',
status: 0,
isTimedOut: true
};
}
throw error;
}
}
}Host Failover Strategy:
The transporter automatically manages host failover:
Caching Strategy: