GET Method - Global Error Handling
Why Use Global Error Handling?
Instead of handling errors in every single GET request, configure it once globally and let hmm-api handle all errors automatically.
Complete Example
import ApiClient, { parseResponseMessage } from "hmm-api";
import { toast } from "sonner";
// Configure once - handles ALL GET requests
const api = new ApiClient({
baseUrl: "https://api.example.com",
returnParsedError: true,
onError: (response) => {
// Handle ALL errors globally
toast.error(response.error);
if (response.status === 401) {
redirectToLogin();
}
},
});
// Usage - No error handling needed!
interface User {
id: number;
name: string;
email: string;
}
const UserComponent = () => {
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(false);
const fetchUsers = async () => {
setLoading(true);
// Simple GET - errors handled automatically
const response = await api.get<User[]>("/users", {
finally: () => setLoading(false),
});
if (response.success) {
setUsers(response.data);
}
};
const fetchUserById = async (id: number) => {
const response = await api.get<User>(`/users/${id}`);
// No error handling needed - global config handles it!
if (response.success) {
return response.data;
}
};
return (
<div>
<button onClick={fetchUsers} disabled={loading}>
{loading ? "Loading..." : "Fetch Users"}
</button>
{/* Render users */}
</div>
);
};
Key Benefits
- No repetitive error handling - Configure once, works everywhere
- Consistent UX - All errors shown the same way
- Clean code - Focus on data, not error handling
- Global auth handling - 401 errors handled automatically
Advanced GET Features (v2.0.0)
Polling with GET
Perfect for checking job status, waiting for data updates, or real-time monitoring:
const checkJobStatus = async (jobId: string) => {
const customPollId = `job-status-${jobId}`;
const result = await api.get(`/jobs/${jobId}/status`, {
poll: {
interval: 2000, // Check every 2 seconds
maxAttempts: 30, // Stop after 30 attempts
pollId: customPollId, // Custom poll ID for this job
stopCondition: (response) => {
// Stop when job is complete
return response.success && response.data.status === "completed";
},
onPollSuccess: (response, attempt) => {
console.log(
`Job ${jobId} - Attempt ${attempt}: ${response.data.progress}%`
);
updateProgressBar(response.data.progress);
},
},
});
// Check if it's a polling result
if ("finalResponse" in result) {
console.log(`Job ${jobId} completed after ${result.attempts} attempts`);
console.log(`Poll ID: ${result.pollId}`); // Custom poll ID
return result.finalResponse.data;
}
};
// Cancel job status checking from anywhere in your app
const cancelJobStatusCheck = (jobId: string) => {
const pollId = `job-status-${jobId}`;
const stopped = api.stopPolling(pollId);
if (stopped) {
console.log(`Cancelled status checking for job ${jobId}`);
}
};
Download Progress with GET
Track download progress for large files:
const downloadFile = async (fileId: string) => {
const response = await api.get(`/files/${fileId}/download`, {
onDownloadProgress: (progress) => {
console.log(`Download: ${progress.percentage}%`);
updateDownloadProgress(progress.percentage);
// Show detailed progress
console.log(`${progress.loaded} / ${progress.total} bytes`);
},
timeout: 60000, // 1 minute timeout for large files
});
if (response.success) {
saveFile(response.data);
}
};
Multiple Polling Operations
Run multiple GET polling operations simultaneously:
const Dashboard = () => {
const [data, setData] = useState({});
// Define poll IDs for better management
const POLL_IDS = {
orders: "dashboard-orders",
inventory: "dashboard-inventory",
system: "dashboard-system",
};
const startMultiplePolling = async () => {
// Start 3 independent polling operations with custom IDs
const [orders, inventory, system] = await Promise.all([
api.get("/dashboard/orders", {
poll: {
interval: 3000,
pollId: POLL_IDS.orders, // Custom poll ID
onPollSuccess: (response) => {
setData((prev) => ({ ...prev, orders: response.data }));
},
},
}),
api.get("/dashboard/inventory", {
poll: {
interval: 5000,
pollId: POLL_IDS.inventory, // Custom poll ID
onPollSuccess: (response) => {
setData((prev) => ({ ...prev, inventory: response.data }));
},
},
}),
api.get("/dashboard/system", {
poll: {
interval: 2000,
pollId: POLL_IDS.system, // Custom poll ID
onPollSuccess: (response) => {
setData((prev) => ({ ...prev, system: response.data }));
},
},
}),
]);
// Verify poll IDs
console.log("Started polls:", {
orders: orders.pollId,
inventory: inventory.pollId,
system: system.pollId,
});
console.log(`Active polls: ${api.getActivePollingCount()}`); // 3
};
const stopSpecificPolling = (type: keyof typeof POLL_IDS) => {
const stopped = api.stopPolling(POLL_IDS[type]);
console.log(`Stopped ${type} polling: ${stopped}`);
};
const stopAllPolling = () => {
api.stopAllPolling();
console.log(`Active polls: ${api.getActivePollingCount()}`); // 0
};
return (
<div>
<button onClick={startMultiplePolling}>Start Dashboard Polling</button>
<button onClick={stopAllPolling}>Stop All Polling</button>
{/* Render dashboard data */}
</div>
);
};
When to Override Global Handling
Only override when you need specific behavior for a particular request:
// Special case: Silent error for optional data
const response = await api.get("/optional-data", {
showError: false, // Don't show toast for this one
onError: (response) => {
console.log("Optional data not available, using defaults");
useDefaultData();
},
});
// Special case: Custom timeout for slow endpoints
const response = await api.get("/heavy-computation", {
timeout: 120000, // 2 minutes for heavy operations
});