Now.js Framework Documentation
HttpClient - Low-level HTTP Client
HttpClient - Low-level HTTP Client
Documentation for HttpClient, the Low-level HTTP Client of Now.js Framework
📋 Table of Contents
- Overview
- Installation and Import
- All Exports
- HttpClient Class
- http Instance
- httpThrow Instance
- simpleFetch Utility
- Interceptors
- CSRF Protection
- Security Features
- Error Handling
- Usage Examples
- API Reference
- Best Practices
Overview
HttpClient is a Low-level HTTP Client built on the Fetch API with modern and secure features, suitable for API calls that require low-level control.
Key Features
- ✅ 4 Exports:
HttpClient,http,httpThrow,simpleFetch - ✅ Interceptors: Request and Response interceptors
- ✅ CSRF Protection: Prevent CSRF attacks
- ✅ Auto Content-Type Detection: Detect and parse response automatically
- ✅ Timeout Support: Set timeout for requests
- ✅ Error Handling: Flexible error management
- ✅ Custom Response Handler: Define custom response handling
- ✅ AbortController Support: Cancel requests
- ✅ FormData/Blob/ArrayBuffer Support: Support various content types
Installation and Import
HttpClient is loaded with Now.js Framework and ready to use immediately via window object:
// No import needed - ready to use
console.log(window.http); // http instance
console.log(window.httpThrow); // httpThrow instance
console.log(window.simpleFetch); // simpleFetch utility
console.log(window.HttpClient); // HttpClient classAll Exports
HttpClient provides 4 main exports:
| Export | Type | throwOnError | Use Case |
|---|---|---|---|
HttpClient |
Class | As configured | Create custom instance |
http |
Instance | false |
General use (safe mode) |
httpThrow |
Instance | true |
Use when need to throw errors |
simpleFetch |
Utility Object | N/A | Lightweight and simple usage |
HttpClient Class
Constructor
Create new HttpClient instance:
const client = new HttpClient(options);Options
| Option | Type | Default | Description |
|---|---|---|---|
baseURL |
string |
'' |
Base URL for all requests |
headers |
object |
{} |
Default headers |
timeout |
number |
30000 |
Timeout in milliseconds |
throwOnError |
boolean |
true |
Throw error on failed response |
responseHandler |
function |
null |
Custom response handler |
csrfCookieName |
string |
'XSRF-TOKEN' |
CSRF cookie name |
csrfTokenSelector |
string |
'meta[name="csrf-token"]' |
CSS selector for CSRF meta tag |
security |
object |
{} |
Security configuration |
Instance Creation Examples
// Basic instance
const api = new HttpClient({
baseURL: 'https://api.example.com',
timeout: 10000
});
// Instance with CSRF protection
const secureApi = new HttpClient({
baseURL: 'https://api.example.com',
security: {
csrf: {
enabled: true,
tokenName: '_token',
headerName: 'X-CSRF-Token'
}
}
});
// Instance with custom response handler
const customApi = new HttpClient({
baseURL: 'https://api.example.com',
responseHandler: async (response) => {
const data = await response.json();
return {
success: response.ok,
result: data,
timestamp: Date.now()
};
}
});Methods
HTTP Methods
// GET request
await client.get(url, options);
// POST request
await client.post(url, data, options);
// PUT request
await client.put(url, data, options);
// DELETE request
await client.delete(url, options);
// PATCH request
await client.patch(url, data, options);
// HEAD request
await client.head(url, options);
// OPTIONS request
await client.options(url, options);Safe Methods (don't throw error)
// Safe GET
await client.getSafe(url, options);
// Safe POST
await client.postSafe(url, data, options);
// Safe PUT
await client.putSafe(url, data, options);
// Safe DELETE
await client.deleteSafe(url, options);Upload Method
// Upload single file
await client.upload('/api/upload', file);
// Upload multiple files
await client.upload('/api/upload', [file1, file2]);
// Upload with additional data
await client.upload('/api/upload', files, {
data: {
title: 'My Upload',
category: 'images'
}
});Configuration Methods
// Set base URL
client.setBaseURL('https://api.example.com');
// Set default header
client.setDefaultHeader('Authorization', 'Bearer token');
// Set default headers
client.setDefaultHeaders({
'X-App-Version': '1.0.0',
'X-Device-ID': 'abc123'
});
// Set timeout
client.setTimeout(60000); // 60 seconds
// Set CSRF token
client.setCsrfToken('token-value');http Instance
Ready-to-use instance with throwOnError: false suitable for general use
Characteristics
- ❌ Doesn't throw errors (need to check
response.okyourself) - ✅ Has
timestampandrequestIdin response - ✅ Auto-parse response by Content-Type
Usage
// GET request
const response = await http.get('/api/users');
if (response.ok) {
console.log(response.data);
console.log('Timestamp:', response.timestamp);
console.log('Request ID:', response.requestId);
} else {
console.error('Error:', response.statusText);
}
// POST request
const response = await http.post('/api/users', {
name: 'John Doe',
email: 'john@example.com'
});
if (response.ok) {
console.log('Created:', response.data);
}Response Object
{
ok: boolean, // true if status 200-299
status: number, // HTTP status code
statusText: string, // HTTP status text
data: any, // Parsed response data
headers: object, // Response headers
url: string, // Request URL
timestamp: number, // Timestamp (http instance only)
requestId: string|null // Request ID from header (http instance only)
}httpThrow Instance
Ready-to-use instance with throwOnError: true suitable for use with try-catch
Characteristics
- ✅ Throws
HttpErroron failed response - ✅ Has
timestampandrequestIdin response - ✅ Return format slightly different from
http
Usage
try {
// GET request
const response = await httpThrow.get('/api/users');
console.log(response.data);
console.log('Message:', response.message);
} catch (error) {
console.error('Error:', error.message);
console.error('Status:', error.status);
console.error('Response:', error.response);
}
// POST request
try {
const response = await httpThrow.post('/api/users', {
name: 'John Doe',
email: 'john@example.com'
});
console.log('Created:', response.data);
} catch (error) {
if (error.status === 422) {
console.error('Validation errors:', error.response.data);
} else {
console.error('Server error:', error.message);
}
}Response Object (Success)
{
status: number, // HTTP status code
data: any, // Parsed response data
message: string, // Message from server or statusText
meta: any, // Meta data from server (if any)
timestamp: number, // Timestamp
headers: object, // Response headers
requestId: string|null // Request ID from header
}HttpError Object (Error)
{
name: 'HttpError',
message: string, // Error message
status: number, // HTTP status code
response: object, // Full response object
timestamp: number // Error timestamp
}simpleFetch Utility
Lightweight fetch wrapper designed for easy and lightweight use, suitable for simple API calls
Characteristics
- ✅ Zero dependencies (uses fetch API only)
- ✅ Auto-parsing response (JSON, Text, Blob)
- ✅ Convenience methods (
.json(),.text(),.postJson()) - ✅ Auto-attach bearer token from localStorage
- ✅ Timeout support (default 15 seconds)
- ✅ Method chaining for configuration
HTTP Methods
Standard Methods (return response object)
// GET request
const response = await simpleFetch.get('/api/users');
if (response.ok) {
console.log(response.data);
}
// POST request
const response = await simpleFetch.post('/api/users', {
name: 'John Doe'
});
// PUT request
const response = await simpleFetch.put('/api/users/1', {
name: 'Jane Doe'
});
// DELETE request
const response = await simpleFetch.delete('/api/users/1');
// PATCH request
const response = await simpleFetch.patch('/api/users/1', {
status: 'active'
});Convenience Methods (return data directly)
// Get JSON data directly
const users = await simpleFetch.json('/api/users');
console.log(users); // Array of users or null
// Get text data directly
const html = await simpleFetch.text('/api/template');
console.log(html); // HTML string or null
// Post JSON and get data directly
const newUser = await simpleFetch.postJson('/api/users', {
name: 'John Doe'
});
console.log(newUser); // Created user object or nullFile Upload
// Upload single file
const response = await simpleFetch.upload('/api/upload', file);
// Upload multiple files
const response = await simpleFetch.upload('/api/upload', [file1, file2]);
// Upload with additional data
const response = await simpleFetch.upload('/api/upload', files, {
title: 'My Photos',
category: 'vacation'
});
// Upload with FormData
const formData = new FormData();
formData.append('file', file);
formData.append('title', 'Photo');
const response = await simpleFetch.upload('/api/upload', formData);Configuration
// Set base URL
simpleFetch.setBaseURL('https://api.example.com');
// Set default headers
simpleFetch.setHeaders({
'X-App-Version': '1.0.0',
'X-Device-ID': 'abc123'
});
// Set single header
simpleFetch.setHeader('X-Custom-Header', 'value');
// Set timeout
simpleFetch.setTimeout(30000); // 30 seconds
// Remove header
simpleFetch.removeHeader('X-Custom-Header');
// Reset configuration
simpleFetch.resetConfig();
// Method chaining
simpleFetch
.setBaseURL('https://api.example.com')
.setTimeout(10000)
.setHeader('X-App-Version', '1.0.0');Auto Bearer Token
simpleFetch automatically retrieves bearer token from localStorage.getItem('auth_token') and adds it to Authorization header:
// If token exists in localStorage
localStorage.setItem('auth_token', 'your-token');
// simpleFetch will automatically add this header:
// Authorization: Bearer your-token
const response = await simpleFetch.get('/api/user/profile');Response Object
{
ok: boolean, // true if status 200-299
status: number, // HTTP status code
statusText: string, // HTTP status text
data: any, // Parsed response data (or null)
headers: object, // Response headers
url: string, // Request URL
error: Error // Error object (if error)
}Interceptors
Interceptors allow you to modify requests or responses before they are sent or received
Request Interceptor
Modify request config before sending:
// Add request interceptor
const removeInterceptor = http.addRequestInterceptor(config => {
// Modify config
config.headers['X-Timestamp'] = Date.now();
config.headers['X-User-Agent'] = navigator.userAgent;
// Must return config
return config;
});
// Remove interceptor
removeInterceptor();Response Interceptor
Handle response after receiving from server:
// Add response interceptor
const removeInterceptor = http.addResponseInterceptor(
// onFulfilled - handle success response
(response) => {
console.log('Response received:', response.status);
// Modify response if needed
response.receivedAt = Date.now();
return response;
},
// onRejected - handle error response
(error) => {
console.error('Response error:', error);
// Modify error or throw
if (error.status === 401) {
// Redirect to login
window.location.href = '/login';
}
throw error;
}
);
// Remove interceptor
removeInterceptor();Interceptor Usage Examples
1. Add Authentication Token
http.addRequestInterceptor(config => {
const token = localStorage.getItem('auth_token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
});2. Logging
// Log requests
http.addRequestInterceptor(config => {
console.log(`[${config.method}] ${config.url}`);
return config;
});
// Log responses
http.addResponseInterceptor(
response => {
console.log(`[${response.status}] ${response.url}`);
return response;
},
error => {
console.error(`[Error] ${error.status} - ${error.message}`);
throw error;
}
);3. Retry on Network Error
http.addResponseInterceptor(
response => response,
async (error) => {
if (error.status === 0 || error.status === 408) {
console.log('Network error, retrying...');
// Retry request
return await http.request(error.url);
}
throw error;
}
);4. Transform Response
http.addResponseInterceptor(response => {
// Transform response format
return {
success: response.ok,
result: response.data,
errors: response.ok ? null : response.data?.errors,
timestamp: Date.now()
};
});5. Rate Limiting
const requestTimestamps = [];
http.addRequestInterceptor(config => {
const now = Date.now();
// Remove timestamps older than 1 minute
const oneMinuteAgo = now - 60000;
while (requestTimestamps.length && requestTimestamps[0] < oneMinuteAgo) {
requestTimestamps.shift();
}
// Check rate limit (max 60 requests/minute)
if (requestTimestamps.length >= 60) {
throw new Error('Rate limit exceeded. Please wait.');
}
requestTimestamps.push(now);
return config;
});CSRF Protection
HttpClient has built-in CSRF protection to prevent Cross-Site Request Forgery attacks
Enable CSRF
const client = new HttpClient({
security: {
csrf: {
enabled: true,
tokenName: '_token',
headerName: 'X-CSRF-Token'
}
}
});How It Works
CSRF token is retrieved from:
- Meta tag (
<meta name="csrf-token" content="token-value">) - Cookie (name
XSRF-TOKENby default)
<!-- In <head> section -->
<meta name="csrf-token" content="your-csrf-token-here">Auto-Attach CSRF Token
Token is automatically attached in:
- Header:
X-CSRF-Token: token-value - Request Body: For POST/PUT/DELETE requests
// Token will be attached automatically
await client.post('/api/delete-item', { id: 123 });
// Request will have:
// Header: X-CSRF-Token: your-token
// Body: { id: 123, _token: 'your-token' }Set CSRF Token Manually
// Set token manually
client.setCsrfToken('new-token-value');
// Token will be used in subsequent requests
await client.post('/api/action', data);CSRF Token Renewal
HttpClient automatically updates token from response header:
// Server sends header: X-CSRF-Token: new-token
const response = await client.post('/api/action', data);
// client.csrfToken will be automatically updated to 'new-token'Security Features
HttpClient has several security features that can be enabled
1. CSRF Protection
Prevent Cross-Site Request Forgery:
const client = new HttpClient({
security: {
csrf: {
enabled: true,
tokenName: '_token',
headerName: 'X-CSRF-Token'
}
}
});2. Rate Limiting
Limit number of requests (requires SecurityManager):
const client = new HttpClient({
security: {
rateLimit: {
enabled: true
}
}
});3. Request Validation
Sanitize request data (requires SecurityManager):
const client = new HttpClient({
security: {
validation: {
enabled: true
}
}
});4. Timeout
Prevent long-hanging requests:
const client = new HttpClient({
timeout: 10000 // 10 seconds
});
// Or set later
client.setTimeout(5000); // 5 seconds5. Same-Origin Credentials
Prevent sending credentials across domains:
const client = new HttpClient();
// Default: credentials: 'same-origin'
await client.get('/api/data');
// Need to send credentials across origin
await client.get('https://api.example.com/data', {
credentials: 'include'
});Error Handling
HttpClient has multiple ways to handle errors
1. Safe Mode (http instance)
Use http instance that doesn't throw errors:
const response = await http.get('/api/users');
if (response.ok) {
console.log('Success:', response.data);
} else {
console.error('Error:', response.status, response.statusText);
// Show error message from server
if (response.data?.message) {
console.error('Server message:', response.data.message);
}
}2. Throw Mode (httpThrow instance)
Use httpThrow instance that throws errors:
try {
const response = await httpThrow.get('/api/users');
console.log('Success:', response.data);
} catch (error) {
console.error('Error:', error.message);
console.error('Status:', error.status);
// Handle error by status code
switch (error.status) {
case 401:
// Redirect to login
window.location.href = '/login';
break;
case 403:
alert('Access denied');
break;
case 404:
alert('Resource not found');
break;
case 422:
// Validation errors
const errors = error.response.data.errors;
console.error('Validation errors:', errors);
break;
case 500:
alert('Server error. Please try again later.');
break;
default:
alert('An error occurred: ' + error.message);
}
}3. Custom Instance
Create instance with custom error handling:
const client = new HttpClient({
throwOnError: false // or true as needed
});
// Override throwOnError per request
const response = await client.get('/api/users', {
throwOnError: true // Throw error only for this request
});4. Error Interceptor
Use response interceptor to handle errors:
http.addResponseInterceptor(
response => response,
error => {
// Log error
console.error('API Error:', error);
// Show notification
if (window.NotificationManager) {
NotificationManager.error(error.message);
}
// Redirect on auth error
if (error.status === 401) {
window.location.href = '/login';
return; // Don't throw
}
// Re-throw other errors
throw error;
}
);5. Timeout Errors
Handle timeout errors:
const response = await http.get('/api/slow-endpoint');
if (!response.ok && response.status === 408) {
console.error('Request timeout');
alert('The server is taking too long to respond. Please try again.');
}HttpError Object
try {
await httpThrow.get('/api/users');
} catch (error) {
console.log(error.name); // 'HttpError'
console.log(error.message); // Error message
console.log(error.status); // HTTP status code
console.log(error.response); // Full response object
console.log(error.timestamp); // Error timestamp
}Usage Examples
1. Simple API Call
// Using simpleFetch
const users = await simpleFetch.json('/api/users');
console.log(users);
// Using http
const response = await http.get('/api/users');
if (response.ok) {
console.log(response.data);
}2. Send JSON Data
// POST
const response = await http.post('/api/users', {
name: 'John Doe',
email: 'john@example.com',
age: 30
});
if (response.ok) {
console.log('Created:', response.data);
}
// PUT
const response = await http.put('/api/users/1', {
name: 'Jane Doe',
email: 'jane@example.com'
});
// PATCH
const response = await http.patch('/api/users/1', {
status: 'active'
});3. File Upload
// Single file upload
const fileInput = document.querySelector('#file');
const file = fileInput.files[0];
const response = await http.upload('/api/upload', file);
if (response.ok) {
console.log('Uploaded:', response.data.url);
}
// Multiple files upload
const files = Array.from(fileInput.files);
const response = await http.upload('/api/upload', files);
// Upload with additional data
const response = await http.upload('/api/upload', file, {
data: {
title: 'Profile Picture',
category: 'avatars'
}
});4. Using FormData
const formData = new FormData();
formData.append('name', 'John Doe');
formData.append('email', 'john@example.com');
formData.append('avatar', file);
const response = await http.post('/api/users', formData);5. File Download
const response = await http.get('/api/reports/download', {
headers: {
'Accept': 'application/pdf'
}
});
if (response.ok) {
// response.data will be Blob
const blob = response.data;
// Create download link
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'report.pdf';
a.click();
URL.revokeObjectURL(url);
}6. Using Query Parameters
// Manual
const response = await http.get('/api/users?page=1&limit=10&sort=name');
// With URLSearchParams
const params = new URLSearchParams({
page: 1,
limit: 10,
sort: 'name'
});
const response = await http.get(`/api/users?${params}`);7. Cancel Request
const controller = new AbortController();
// Start request
const responsePromise = http.get('/api/large-data', {
signal: controller.signal
});
// Cancel after 5 seconds
setTimeout(() => {
controller.abort();
}, 5000);
try {
const response = await responsePromise;
console.log(response.data);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request cancelled');
}
}8. Using Custom Headers
const response = await http.get('/api/data', {
headers: {
'X-Custom-Header': 'value',
'Accept-Language': 'en',
'X-App-Version': '1.0.0'
}
});9. Using Authentication
// Bearer token
http.setDefaultHeader('Authorization', 'Bearer your-token-here');
// Or use interceptor
http.addRequestInterceptor(config => {
const token = localStorage.getItem('auth_token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
});
// Basic auth
const username = 'user';
const password = 'pass';
const credentials = btoa(`${username}:${password}`);
http.setDefaultHeader('Authorization', `Basic ${credentials}`);10. Using Base URL
// Set base URL
http.setBaseURL('https://api.example.com');
// Usage
await http.get('/users'); // https://api.example.com/users
await http.get('/posts'); // https://api.example.com/posts
// Override base URL with absolute URL
await http.get('https://other-api.com/data'); // https://other-api.com/data11. Parallel Requests
// Wait for all requests to complete
const [users, posts, comments] = await Promise.all([
http.get('/api/users'),
http.get('/api/posts'),
http.get('/api/comments')
]);
console.log('Users:', users.data);
console.log('Posts:', posts.data);
console.log('Comments:', comments.data);
// Wait for first completed request
const response = await Promise.race([
http.get('/api/fast-endpoint'),
http.get('/api/slow-endpoint')
]);12. Retry Logic
async function fetchWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await http.get(url);
if (response.ok) {
return response;
}
// Retry on server errors
if (response.status >= 500 && i < maxRetries - 1) {
console.log(`Retry ${i + 1}/${maxRetries}...`);
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
continue;
}
return response;
}
}
const response = await fetchWithRetry('/api/unstable-endpoint');13. Progress Tracking (Upload)
// Use XMLHttpRequest for progress tracking
function uploadWithProgress(url, file, onProgress) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append('file', file);
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
const percent = (e.loaded / e.total) * 100;
onProgress(percent);
}
});
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(new Error(xhr.statusText));
}
});
xhr.addEventListener('error', () => reject(new Error('Upload failed')));
xhr.open('POST', url);
xhr.send(formData);
});
}
// Usage
const file = document.querySelector('#file').files[0];
const result = await uploadWithProgress('/api/upload', file, (percent) => {
console.log(`Uploading: ${percent.toFixed(2)}%`);
});API Reference
HttpClient Class
Constructor
new HttpClient(options?: HttpClientOptions): HttpClientProperties
| Property | Type | Description |
|---|---|---|
baseURL |
string |
Base URL for requests |
defaultHeaders |
object |
Default headers |
timeout |
number |
Timeout (ms) |
throwOnError |
boolean |
Throw error on non-2xx |
csrfToken |
string \| null |
CSRF token |
interceptors |
object |
Request/Response interceptors |
Methods
HTTP Methods
get(url: string, options?: RequestOptions): Promise<Response>
post(url: string, data?: any, options?: RequestOptions): Promise<Response>
put(url: string, data?: any, options?: RequestOptions): Promise<Response>
delete(url: string, options?: RequestOptions): Promise<Response>
patch(url: string, data?: any, options?: RequestOptions): Promise<Response>
head(url: string, options?: RequestOptions): Promise<Response>
options(url: string, options?: RequestOptions): Promise<Response>Safe Methods
getSafe(url: string, options?: RequestOptions): Promise<Response>
postSafe(url: string, data?: any, options?: RequestOptions): Promise<Response>
putSafe(url: string, data?: any, options?: RequestOptions): Promise<Response>
deleteSafe(url: string, options?: RequestOptions): Promise<Response>Other Methods
upload(url: string, files: File | File[], options?: UploadOptions): Promise<Response>
request(url: string, options?: RequestOptions): Promise<Response>Configuration Methods
setBaseURL(url: string): void
setDefaultHeader(name: string, value: string): void
setDefaultHeaders(headers: object): void
setTimeout(timeout: number): void
setCsrfToken(token: string): voidInterceptor Methods
addRequestInterceptor(fn: (config) => config | Promise<config>): () => void
addResponseInterceptor(onFulfilled?: (response) => response, onRejected?: (error) => error): () => voidsimpleFetch Utility
Methods
// HTTP Methods
fetch(url: string, options?: RequestOptions): Promise<Response>
get(url: string, options?: RequestOptions): Promise<Response>
post(url: string, data?: any, options?: RequestOptions): Promise<Response>
put(url: string, data?: any, options?: RequestOptions): Promise<Response>
delete(url: string, options?: RequestOptions): Promise<Response>
patch(url: string, data?: any, options?: RequestOptions): Promise<Response>
// Convenience Methods
json(url: string, options?: RequestOptions): Promise<any>
text(url: string, options?: RequestOptions): Promise<string>
postJson(url: string, data: any, options?: RequestOptions): Promise<any>
// Upload Method
upload(url: string, files: File | File[] | FormData, data?: object, options?: RequestOptions): Promise<Response>
// Configuration Methods
setBaseURL(url: string): simpleFetch
setHeaders(headers: object): simpleFetch
setHeader(name: string, value: string): simpleFetch
setTimeout(timeout: number): simpleFetch
removeHeader(name: string): simpleFetch
resetConfig(): simpleFetchBest Practices
1. ✅ Choose the Right Export
// ❌ Bad: Use HttpClient class when unnecessary
const client = new HttpClient();
const response = await client.get('/api/users');
// ✅ Good: Use simpleFetch or http instance
const users = await simpleFetch.json('/api/users');
// or
const response = await http.get('/api/users');2. ✅ Set Base URL
// ❌ Bad: Full URL every time
await http.get('https://api.example.com/users');
await http.get('https://api.example.com/posts');
// ✅ Good: Set base URL
http.setBaseURL('https://api.example.com');
await http.get('/users');
await http.get('/posts');3. ✅ Use Interceptors for Common Tasks
// ❌ Bad: Add token every time
const token = localStorage.getItem('token');
await http.get('/api/users', {
headers: { 'Authorization': `Bearer ${token}` }
});
// ✅ Good: Use interceptor
http.addRequestInterceptor(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
});
await http.get('/api/users');4. ✅ Handle Errors Appropriately
// ❌ Bad: Don't check response
const response = await http.get('/api/users');
console.log(response.data); // may be null
// ✅ Good: Check response.ok
const response = await http.get('/api/users');
if (response.ok) {
console.log(response.data);
} else {
console.error('Error:', response.statusText);
}
// ✅ Better: Use httpThrow
try {
const response = await httpThrow.get('/api/users');
console.log(response.data);
} catch (error) {
console.error('Error:', error.message);
}5. ✅ Use AbortController for Long Requests
// ✅ Good: Can cancel
const controller = new AbortController();
button.addEventListener('click', () => {
http.get('/api/large-data', {
signal: controller.signal
});
});
cancelButton.addEventListener('click', () => {
controller.abort();
});6. ✅ Specify Correct Content-Type
// ❌ Bad: Specify Content-Type for FormData
await http.post('/api/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' }
});
// ✅ Good: Let browser set it
await http.post('/api/upload', formData);7. ✅ Enable CSRF Protection
// ✅ Good: Enable CSRF protection
const client = new HttpClient({
security: {
csrf: {
enabled: true,
headerName: 'X-CSRF-Token'
}
}
});8. ✅ Set Appropriate Timeout
// ❌ Bad: Same timeout for all requests
http.setTimeout(5000);
// ✅ Good: Different timeout by request type
http.setTimeout(30000); // Default
await http.get('/api/quick', { timeout: 5000 });
await http.post('/api/process', data, { timeout: 120000 });9. ✅ Cleanup Interceptors
// ❌ Bad: Don't cleanup
http.addRequestInterceptor(config => {
// ...
return config;
});
// ✅ Good: Keep remove function
const removeInterceptor = http.addRequestInterceptor(config => {
// ...
return config;
});
// Cleanup when not needed
removeInterceptor();10. ✅ Handle Network Errors
const response = await http.get('/api/users');
if (!response.ok) {
if (response.status === 0 || response.status === 408) {
// Network error or timeout
alert('Cannot connect to server');
} else if (response.status >= 500) {
// Server error
alert('Server error. Please try again later.');
} else {
// Other errors
alert('An error occurred: ' + response.statusText);
}
}Summary
Choose the Right Export
| If you need... | Use... |
|---|---|
| Simplicity, lightweight | simpleFetch |
| Safe mode (doesn't throw error) | http |
| Automatic error throwing | httpThrow |
| Custom configuration | new HttpClient() |
Key Features
| Feature | HttpClient | http | httpThrow | simpleFetch |
|---|---|---|---|---|
| Interceptors | ✅ | ✅ | ✅ | ❌ |
| CSRF Protection | ✅ | ✅ | ✅ | ❌ |
| Throw on Error | As configured | ❌ | ✅ | ❌ |
| Custom Handler | ✅ | ✅ | ✅ | ❌ |
| Auto Bearer Token | ❌ | ❌ | ❌ | ✅ |
| Convenience Methods | ❌ | ❌ | ❌ | ✅ |