@mrzr/api-client

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=b

Template 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 keys

JSON 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:

statusCodeMeaning
0Network failure (offline, DNS, CORS), or the request was canceled (canceled: true)
408The request timed out (timeout, default 30 s)

Useful per-request options

OptionDoes
timeoutTimeout in ms for this call
headersExtra headers
skipAuthDon't send the token (public endpoints)
fullDataDon't unwrap { data }
responseTypeHow to read the body
afterFuncTransform the payload on success

Native fetch options (signal, cache, keepalive, …) are passed through. For every option, see Client options.

On this page