# Requests & Errors (/docs/requests)



## The five methods [#the-five-methods]

```ts
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 [#urls-and-query-strings]

```ts
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 [#what-you-get-back]

Every call resolves to the same envelope:

```ts
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 [#errors]

By default a failure **throws** an `ApiError`. This is what TanStack Query, SWR and Vue Query expect.

```ts
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:

```ts
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 [#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](/docs/client-options#per-request-options).
