Requests & Errors
Make GET, POST, PUT, PATCH and DELETE requests with @mrzr/api-client, build URLs and query strings, read the response and handle ApiError.
The five methods
api.get<R>(url, config?)
api.post<R>(url, body?, config?)
api.put<R>(url, body?, config?)
api.patch<R>(url, body?, config?)
api.delete<R>(url, config?)Plain objects are sent as JSON. Content-Type is only set when there is a body, so a cross-origin GET doesn't trigger a CORS preflight.
URLs and query strings
api.get("/orgs/{org}/users", {
addTemplateToUrl: { org: "acme" }, // → /orgs/acme/users
params: { page: 1, filter: { active: true }, tag: ["a", "b"] },
});
// → /orgs/acme/users?page=1&filter[active]=true&tag=a&tag=bTemplate values are encoded as a single path segment, so { id: "1/../admin" } can't escape into another path. Empty values (null, undefined, "") are left out of the query string.
What you get back
Every call resolves to the same envelope:
const res = await api.get<User>("/me");
res.data // the payload: unwrapped from { data } when the server wraps it
res.body // the whole body, when data was unwrapped (pagination meta, links…)
res.statusCode // 200
res.status // true for 2xx
res.message // the server's "message", if any
res.headers // response headers, lowercased keysJSON is parsed for you. Files, images and PDFs come back as a Blob. To choose the format yourself, pass responseType: "json" | "text" | "blob" | "arrayBuffer".
Errors
By default a failure throws an ApiError. This is what TanStack Query, SWR and Vue Query expect.
try {
await api.post("/users", form);
} catch (e) {
if (e instanceof ApiError) {
e.statusCode // 422
e.message // "Validation failed"
e.errors // { email: ["already taken"] }
}
}If you prefer to check a flag over catching errors, turn throwing off for one call or for the whole client:
const res = await api.get("/users", { throwError: false });
if (!res.status) showError(res.message);Some failures never reach the server, so the client sets the status code itself:
statusCode | Meaning |
|---|---|
0 | Network failure (offline, DNS, CORS), or the request was canceled (canceled: true) |
408 | The request timed out (timeout, default 30 s) |
Useful per-request options
| Option | Does |
|---|---|
timeout | Timeout in ms for this call |
headers | Extra headers |
skipAuth | Don't send the token (public endpoints) |
fullData | Don't unwrap { data } |
responseType | How to read the body |
afterFunc | Transform the payload on success |
Native fetch options (signal, cache, keepalive, …) are passed through. For every option, see Client options.
Live Demo
Run @mrzr/api-client in your browser. Watch many 401s trigger a single token refresh, cancel in-flight requests and check where the token is kept.
Authentication
Log users in with bearer tokens or httpOnly cookies. Choose where tokens are stored, restore a cookie session on page load and enable CSRF protection.