utils.ts
Overview
The `utils.ts` file provides a set of utility functions and configurations primarily focused on error handling, HTTP request retry logic, pagination validation, and JSON-RPC request ID generation. These utilities support robust API interaction by standardizing error transformation, enforcing safe page size limits, and enabling resilient HTTP client behavior with configurable retry strategies. This file is intended to be a foundational helper module used across various parts of the application that require HTTP communication and error management.
Detailed Descriptions
Constants
MAX_PAGE_SIZE: number
Description: Defines the maximum allowed page size for paginated API requests.
Value:
100Usage: Used to validate that page size requests do not exceed this limit.
Functions
validatePageSize(pageSize: number): void
Purpose: Validates that the provided
pageSizeargument is within acceptable bounds.Parameters:
pageSize(number): The requested size of a page in a paginated response.
Returns: Nothing. Throws an error if validation fails.
Throws:
ApiErrorifpageSize≤ 0 or ifpageSize>MAX_PAGE_SIZE.Usage Example:
try { validatePageSize(50) // Passes validation validatePageSize(0) // Throws ApiError: "page size must be greater than 0" } catch (error) { console.error(error) }Implementation Details:
Throws a
422 Bad Requesterror with a descriptive message if validation fails.Ensures that API consumers do not request invalid or excessively large pages.
handleError(err: unknown): ApiError
Purpose: Normalizes different types of errors into a consistent
ApiErrorobject.Parameters:
err(unknown): The error object to be transformed.
Returns: An instance of
ApiErrorthat encapsulates error status, status text, and message.Usage Example:
try { // some code that might throw different error types } catch (error) { const apiError = handleError(error) console.error(apiError.status, apiError.message) }Implementation Details:
Checks if the error is already an instance of
ApiErrorand returns it directly.Handles Axios errors by extracting status, statusText, and error messages from the HTTP response.
Handles
BlockbookApiError(custom error from@shapeshiftoss/blockbook).Fallbacks to a generic
Internal Server Errorwith status 500 for unknown error types.
Integration:
Useful in API interaction layers to unify error handling and messaging.
createAxiosRetry(config: RetryConfig, axiosParams?: CreateAxiosDefaults): axios.AxiosInstance
Purpose: Creates an Axios HTTP client instance with automatic retry capabilities based on network or server errors.
Parameters:
config(RetryConfig): Configuration object with optional properties:retries(number) - Number of retry attempts (default: 3).delayFactor(number) - Base delay factor in milliseconds for exponential backoff (default: 500).
axiosParams(CreateAxiosDefaults) - Optional Axios configuration to customize the Axios instance.
Returns: An Axios instance configured with retry logic.
Usage Example:
const axiosClient = createAxiosRetry({ retries: 5, delayFactor: 1000 }) axiosClient.get('https://api.example.com/data') .then(response => console.log(response.data)) .catch(error => console.error(handleError(error)))Implementation Details:
Uses the
axios-retrylibrary to add retry support.Retries on:
Network errors or idempotent request errors.
HTTP status codes in the range 405-599 (excluding 404).
Timeout errors indicated by
ECONNABORTED.
Applies exponential backoff delay between retries, skipping delay if the error was due to timeout (
ECONNABORTED).Resets timeout on each retry attempt.
Integration:
Used to enhance reliability of HTTP requests when communicating with unstable or rate-limited APIs.
exponentialDelay(retryCount: number): Promise<void>
Purpose: Provides a delay promise that resolves after an exponential backoff period.
Parameters:
retryCount(number): The number of retry attempts already made.
Returns: A
Promisethat resolves after a delay.Usage Example:
await exponentialDelay(3) // Waits for delay based on 3rd retry attemptImplementation Details:
Utilizes
axiosRetry.exponentialDelaywith a base delay of 500ms.Useful for manual implementation of retry logic or delay between attempts.
rpcId(): number
Purpose: Generates a unique, incrementing integer ID for JSON-RPC requests.
Parameters: None.
Returns: A positive integer representing the next RPC ID.
Usage Example:
const id1 = rpcId() // e.g., 123456 const id2 = rpcId() // id1 + 1Implementation Details:
Starts with a random initial value between 0 and 999,999.
Increments the ID by 1 on each call.
Applies a bitmask to keep the ID within 31-bit positive integer range.
Skips zero ID (resets to 1 if it wraps to zero).
Integration:
Used in JSON-RPC client implementations to track request-response pairs uniquely.
Important Implementation Details and Algorithms
Error Handling: The
handleErrorfunction provides a robust normalization mechanism for errors originating from multiple sources (custom API errors, Axios, and external Blockbook API errors). This approach prevents error leakage and ensures consistent error handling downstream.Retry Logic: The retry mechanism implemented with
axios-retryincludes a sophisticated condition that retries not only network errors but also certain server errors (status codes 405-599). The exponential backoff delay helps mitigate rapid request flooding, improving resilience.RPC ID Generation: The
rpcIdfunction uses a bitmask to keep the ID within the 31-bit positive integer range, avoiding issues with JavaScript number overflow and maintaining compatibility with typical JSON-RPC ID expectations.
Interactions with Other Parts of the System
ApiError: This class is imported and used extensively to represent standardized API errors. It is expected to be defined elsewhere in the project and likely used throughout the codebase for error handling.Axios HTTP Client: This file configures Axios instances with retry capabilities, which are likely used by network service modules or API clients in the application.
Blockbook API: The file imports and handles errors from the
@shapeshiftoss/blockbookpackage, indicating integration with blockchain-related API services.Pagination: The
validatePageSizefunction enforces pagination constraints, ensuring that API consumers respect backend limits.
Overall, `utils.ts` acts as a foundational utility module supporting network communication, error handling, and API request validation across the application.
Mermaid Flowchart Diagram
flowchart TD
A[validatePageSize(pageSize)] -->|throws ApiError if invalid| B[ApiError]
C[handleError(err)] --> D{Error Type?}
D -->|ApiError| E[Return err]
D -->|AxiosError| F[Create ApiError from Axios response]
D -->|BlockbookApiError| G[Create ApiError from Blockbook response]
D -->|Generic Error| H[Create ApiError with 500 status]
D -->|Unknown| H
I[createAxiosRetry(config, axiosParams)] --> J[Create axios instance]
J --> K[Apply axiosRetry with config]
K -->|RetryCondition| L[Network errors, 405-599 status, timeout]
K -->|RetryDelay| M[Exponential backoff delay]
N[exponentialDelay(retryCount)] --> M
O[rpcId()] --> P[Increment and return unique RPC ID]
Summary
The `utils.ts` file provides robust and reusable utilities essential for:
Validating pagination parameters.
Standardizing error handling across different error types.
Creating Axios HTTP clients with built-in retry strategies for network resilience.
Generating unique IDs for JSON-RPC calls.
It interacts closely with the error handling architecture (`ApiError`), network request layers, and external blockchain APIs, making it a critical support module in the application’s infrastructure.