Introduction
Velocity is a high-performance, zero-dependency HTTP client designed for modern web applications. Built on top of the native Fetch API, it provides a powerful abstraction layer that handles common tasks like JSON parsing, request/response interceptors, sequential polling, and automatic retries without adding bulk to your bundle.
Key Features
• Zero external dependencies — leverages native Fetch and AbortController. • Type-safe by default — written in TypeScript with deep generic support. • Built-in Sequential Polling — perfect for background jobs and status checks. • Advanced Retry Logic — exponential backoff and custom retry conditions. • Interceptor Hooks — modify requests and responses globally. • Lightweight & Universal — works in Browser, Node.js, and Edge environments.
Getting Started
Velocity is available via NPM and other package managers. It requires Node.js 18 or later for server-side usage.
Installation
Or using Yarn/PNPM:
Your First Request
The quickest way to start is by creating a new instance. While you can use the static methods, creating an instance allows you to share configuration across multiple requests.
The Client Instance
The Velocity constructor takes a configuration object that sets the default behavior for all requests made through that instance.
Overriding Configuration
You can override the instance defaults on a per-request basis by passing a configuration object as the last argument to any request method.
Core Requests
Velocity provides shorthand methods for all common HTTP verbs. Each method is generic, allowing you to define the expected response data type.
GET Requests
Used to retrieve data. Query parameters can be passed via the 'params' object in the configuration.
POST, PUT, PATCH
These methods accept a 'data' object as the second argument. Velocity automatically stringifies objects to JSON and sets the 'Content-Length' (where applicable).
DELETE & Others
DELETE requests usually don't have a body, but you can still pass configuration as the second argument.
Interceptors (Hooks)
Interceptors allow you to run code before a request is sent or after a response is received. They are powerful tools for cross-cutting concerns like authentication, logging, and error normalization.
Request Interceptors (onRequest)
Use onRequest to modify the configuration before it reaches the fetch executor. This is the ideal place to inject dynamic authentication tokens from localStorage or a state manager.
Response Interceptors (onResponse)
Response interceptors allow you to transform the response data or handle errors globally before they reach your try/catch blocks.
Ejecting Interceptors
Both onRequest and onResponse return an object with an 'eject' method, allowing you to remove the interceptor later if needed.
Sequential Polling
Velocity includes a first-class sequential polling engine. Unlike setInterval, it waits for each request to complete (or fail) before starting the timer for the next attempt. This prevents 'request piling' and ensures your backend isn't overwhelmed.
Manual Cancellation
You can stop an active polling sequence at any time using the instance's cancelPolling() method.
Retry Mechanism
Network flakiness happens. Velocity can automatically retry failed requests based on your criteria.
Custom Retry Conditions
For more complex logic, use the 'shouldRetry' predicate.
Timeout & Cancellation
Managing request lifecycles is crucial for performance and user experience. Velocity provides robust support for both automatic timeouts and manual cancellation.
Request Timeouts
You can set a timeout in milliseconds. If the request takes longer, it will be aborted and a TimeoutError will be thrown.
Manual Cancellation (AbortController)
Velocity fully supports the native AbortSignal API. This is especially useful in React components to cancel requests on unmount.
File Handling
Uploading and downloading files is straightforward with Velocity.
Uploading Files
To upload files, use FormData. When using FormData, you should explicitly set the 'Content-Type' header to null so the browser can automatically set it with the correct boundary.
Downloading Files
Use the 'responseType' option to receive data as a Blob or ArrayBuffer.
TypeScript Mastery
Velocity is built with TypeScript from the ground up, offering deep type safety for every part of your API layer.
Strict Response Typing
Every request method accepts a generic type parameter representing the structure of the returned data. This flows through to the .data property of the response.
Typing Configurations & Hooks
You can use the exported types to create reusable configuration objects or typed interceptors.
Handling Error Types
Velocity exports a 'VelocityError' class and a 'VelocityErrorKind' type to help you handle different failure scenarios gracefully.
Best Practices
To get the most out of Velocity in production, we recommend following these patterns.
Centralized API Service
Instead of importing Velocity everywhere, create a centralized service file. This makes it easier to manage base URLs and global interceptors.
React Integration
When using Velocity inside React components, always use an AbortController in useEffect to prevent memory leaks and state updates on unmounted components.
Environment Variables
Never hardcode your baseURL. Use environment variables to switch between development, staging, and production environments.
Common Gotchas
Even with a simple API, there are a few common pitfalls to be aware of when working with HTTP clients and the Fetch API.
Missing 'return' in Interceptors
Interceptors are pipelines. If you forget to return the config or response object, the chain will break, and your request will likely hang or fail.
File Uploads & Content-Type
When sending FormData, browsers need to set a specific 'boundary' string in the Content-Type header. If you manually set 'Content-Type': 'multipart/form-data', it will lack this boundary and the server will fail to parse the files.
React State Updates on Unmount
If a request finishes after a component has unmounted, updating state will cause a warning (and potentially memory leaks). Always use an AbortController to cancel pending requests.
React Integration
Velocity is ideally suited for React applications. While you can use it directly in useEffect, we recommend a reactive hook pattern to handle loading states, errors, and automatic cancellation gracefully.
The 'useFetch' Pro Hook
Copy this hook into your project (e.g., hooks/useFetch.ts). it features deep dependency tracking and automatic AbortController management.
Example Usage
Here is how you would use the hook in a real-world component to fetch a list of users.
Real-world Recipes
These patterns show how to solve common production challenges using Velocity.
JWT Auth with Refresh Tokens
A robust pattern for handling expired tokens. If a request fails with 401, we try to refresh the token and then replay the original request.
Handling Paginated APIs
A simple helper to fetch all pages of a resource.
Community & Support
Velocity is an open-source project and we love contributions from the community!
Contributing
Found a bug or have a feature request? Open an issue on our GitHub repository. We welcome pull requests for bug fixes, documentation improvements, and new features.
Need Help?
• GitHub Discussions: For general questions and architectural advice. • Stack Overflow: Use the 'velocity-http' tag. • Twitter: Tag us @velocity_http for quick updates.
API Reference
A quick reference for the most common methods and configuration options.
Velocity Instance Methods
• get<T>(url, config) - Make a GET request. • post<T>(url, data, config) - Make a POST request. • put<T>(url, data, config) - Make a PUT request. • patch<T>(url, data, config) - Make a PATCH request. • delete<T>(url, config) - Make a DELETE request. • request<T>(config) - Generic request method. • onRequest(hook) - Add a request interceptor. • onResponse(hook) - Add a response interceptor. • cancelPolling() - Abort any active polling sequence.
VelocityConfig Options
• baseURL?: string - Prepended to every relative URL. • headers?: HeadersInit - Request headers. • params?: Record<string, any> - URL query parameters. • timeout?: number - Request timeout in ms (default 30000). • responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' - How to parse response. • signal?: AbortSignal - Native AbortSignal for manual cancellation. • withCredentials?: boolean - Send cookies with cross-origin requests.
RetryOptions
• attempts: number - Number of retry attempts on failure. • delay?: number - Milliseconds to wait between retries. • statuses?: number[] - HTTP status codes that trigger a retry. • shouldRetry?: (response, attempt) => boolean - Custom retry predicate.
PollOptions
• interval: number - Milliseconds between each poll attempt. • maxAttempts?: number - Hard cap on total attempts. • validate: (data, response, attempt) => boolean | Promise<boolean> - Return true to stop polling.
VelocityResponse Object
• data: T - The parsed response body. • status: number - HTTP status code. • statusText: string - HTTP status message. • headers: Headers - Response headers object. • config: VelocityConfig - The configuration used for the request. • ok: boolean - True if status is 2xx.