@philiprehberger/http-client

Type-safe fetch wrapper with interceptors, retries, and base URL support
Installation
npm install @philiprehberger/http-client
Usage
Basic
import { createClient } from '@philiprehberger/http-client';
const api = createClient({
baseURL: 'https://api.example.com',
timeout: 5000,
});
const user = await api.get<User>('/users/1');
const created = await api.post<User>('/users', { body: { name: 'Alice' } });
await api.put<User>('/users/1', { body: { name: 'Bob' } });
await api.patch<User>('/users/1', { body: { name: 'Bob' } });
await api.delete('/users/1');
await api.head('/users/1');
await api.options('/users');
Query Parameters
const users = await api.get<User[]>('/users', {
params: { page: 2, limit: 10, active: true },
});
// GET /users?page=2&limit=10&active=true
Auth
const api = createClient({
baseURL: 'https://api.example.com',
auth: { type: 'bearer', token: 'my-token' },
});
// Or basic auth:
const api = createClient({
baseURL: 'https://api.example.com',
auth: { type: 'basic', username: 'user', password: 'pass' },
});
Retry
const api = createClient({
baseURL: 'https://api.example.com',
retry: {
maxAttempts: 3,
retryOn: [500, 502, 503],
backoff: 1000,
backoffStrategy: 'exponential', // default, or 'linear'
jitter: true, // add randomized variation
maxBackoff: 30000, // cap maximum wait
},
});
Interceptors
// Request interceptor
api.onRequest((req) => {
req.headers.set('X-Request-Id', crypto.randomUUID());
return req;
});
// Response interceptor
api.onResponse((res) => {
console.log(`${res.url} → ${res.status} (${res.duration}ms)`);
return res;
});
Timeout
// Default timeout for all requests
const api = createClient({ timeout: 5000 });
// Per-request override
await api.get('/slow-endpoint', { timeout: 30000 });
Response Type
// Force response parsing regardless of Content-Type header
const html = await api.get<string>('/page', { responseType: 'text' });
const data = await api.get<Blob>('/file', { responseType: 'blob' });
const buf = await api.get<ArrayBuffer>('/binary', { responseType: 'arrayBuffer' });
const json = await api.get<MyType>('/data', { responseType: 'json' });
Abort Signal
const controller = new AbortController();
await api.get('/data', { signal: controller.signal });
controller.abort();
Error Handling
import { HttpError } from '@philiprehberger/http-client';
try {
await api.get('/not-found');
} catch (error) {
if (error instanceof HttpError) {
error.status; // 404
error.statusText; // 'Not Found'
error.url; // full URL
error.body; // parsed response body
}
}
API
createClient(options?: ClientOptions)
Returns an HTTP client with the following methods:
| Method | Signature | Description |
|---|
get | <T>(path, opts?) => Promise<T> | GET request. |
post | <T>(path, opts?) => Promise<T> | POST request. |
put | <T>(path, opts?) => Promise<T> | PUT request. |
patch | <T>(path, opts?) => Promise<T> | PATCH request. |
delete | <T>(path, opts?) => Promise<T> | DELETE request. |
head | <T>(path, opts?) => Promise<T> | HEAD request. |
options | <T>(path, opts?) => Promise<T> | OPTIONS request. |
onRequest | (interceptor) => void | Add a request interceptor. |
onResponse | (interceptor) => void | Add a response interceptor. |
ClientOptions
| Property | Type | Description |
|---|
baseURL | string | Prepended to all request paths. |
headers | Record<string, string> | Default headers for all requests. |
timeout | number | Default timeout in ms. |
retry | RetryConfig | Retry configuration. |
auth | AuthConfig | Auth configuration (bearer or basic). |
RetryConfig
| Property | Type | Default | Description |
|---|
maxAttempts | number | 1 | Total attempts (1 = no retry). |
retryOn | number[] | (status) => boolean | None | HTTP status codes to retry on. |
backoff | number | 1000 | Base backoff in ms. |
backoffStrategy | 'linear' | 'exponential' | 'exponential' | Backoff growth strategy. |
jitter | boolean | false | Add random variation to backoff. |
maxBackoff | number | 30000 | Maximum backoff cap in ms. |
RequestOptions
| Property | Type | Description |
|---|
headers | Record<string, string> | Per-request headers (merged with defaults). |
params | Record<string, string | number | boolean> | Query parameters. |
body | unknown | Request body (auto-serialized to JSON). |
timeout | number | Per-request timeout override. |
signal | AbortSignal | Abort signal for cancellation. |
responseType | 'json' | 'text' | 'blob' | 'arrayBuffer' | Force response parsing method (overrides Content-Type auto-detect). |
HttpError
| Property | Type | Description |
|---|
status | number | HTTP status code. |
statusText | string | HTTP status text. |
url | string | Request URL. |
body | unknown | Parsed response body. |
Development
npm install
npm run build
npm test
Support
If you find this project useful:
⭐ Star the repo
🐛 Report issues
💡 Suggest features
❤️ Sponsor development
🌐 All Open Source Projects
💻 GitHub Profile
🔗 LinkedIn Profile
License
MIT