One error object.
No matter where it came from.
Axios, fetch, or anything else — universal-api-errors normalizes it into one predictable, fully-typed shape. Stop writing if (error.response?.status === 401) in every project.
Only need Axios or fetch, not both? Install just the one adapter instead.
Every project re-writes this
A different pile of ifchecks per backend, per project, forever — because every API spells "unauthorized" differently.
Before
try { await api.getUser(id);} catch (error) { if (error.response?.status === 401) { // ... } if (error.response?.data?.message) { // ... } if (error.code === "ERR_NETWORK") { // ... } if (error.message.includes("timeout")) { // ... } // every backend spells these differently — repeat per project}After
import { parseAxiosError } from "@harshilrajput/universal-api-errors-axios";try { await api.getUser(id);} catch (err) { const error = parseAxiosError(err); error.message; // "Token Expired" error.status; // 401 error.retryable; // false error.isUnauthorized; // true}What's actually in the box
Everything below is shipped, tested, and published — not a roadmap slide.
Works with what you already use
Dedicated adapters for Axios and fetch, plus a React Query integration. The core parser also duck-types ky, superagent, and Node's error codes — no adapter needed for those.
Building an adapter for something else? See what's planned or open an issue on GitHub.
The same shape, every time
Pick your client — the output is identical.
import axios from "axios";import { parseAxiosError } from "@harshilrajput/universal-api-errors-axios";try { await axios.get("/api/user");} catch (err) { const error = parseAxiosError(err); if (error.isUnauthorized) return redirectToLogin(); if (error.isValidation) return showFieldErrors(error.validation); if (error.shouldRetry()) return retry(); showToast(error.message);}