# Bring Your Own Backend (https://v1.s3.dimah.dev/docs/react/custom-backend)

`defineApi` type-checks a complete `S3Api` implementation and returns it
unchanged. Your routes, transport, and server framework are up to you; they do
not need to match [`@dimah-s3/server`](https://v1.s3.dimah.dev/docs/server). Mount the result with
`S3Provider` as shown in [React Setup](https://v1.s3.dimah.dev/docs/react/setup).

Each `S3Api` method must accept the documented input and return JSON with
every **required field** in the response tables. Optional fields may be omitted;
missing required fields break the hooks.
Every object operation includes a required `route` name; `catalog()` is the
exception. Upload and multipart init do **not** send `key` — your backend
generates it and returns it.

Input types: `Parameters<S3Api["upload"]>`. Response types are exported from
`@dimah-s3/core`.

## Flows [#flows]

| Flow           | Methods                                                             | Doc                                               |
| -------------- | ------------------------------------------------------------------- | ------------------------------------------------- |
| Route policies | `catalog`                                                           | [React Setup](https://v1.s3.dimah.dev/docs/react/setup)                  |
| Simple upload  | `upload` → browser uploads to S3 → `confirm`                        | [Upload](https://v1.s3.dimah.dev/docs/react/custom-backend/upload)       |
| Download       | `download`                                                          | [Download](https://v1.s3.dimah.dev/docs/react/custom-backend/download)   |
| Delete         | `delete` or `deleteMany`                                            | [Delete](https://v1.s3.dimah.dev/docs/react/custom-backend/delete)       |
| Multipart      | `init` → `signPart` → `complete` or `abort` · `listParts` to resume | [Multipart](https://v1.s3.dimah.dev/docs/react/custom-backend/multipart) |

### Route catalog [#route-catalog]

`catalog()` returns the enabled operations and upload constraints for every
named route. The upload hook uses this response when `accept`, `maxFileSize`,
or multipart behavior is not overridden on the client.

<AutoTypeTable
  path="packages/core/src/schema/catalog.ts"
  name="RouteCatalogResponse"
/>

```ts
async catalog() {
  const res = await fetch("/api/files/routes");
  if (!res.ok) throw new Error(await res.text());
  return res.json();
}
```

## Skeleton [#skeleton]

Merge the methods from each page into one `defineApi` call:

```ts title="lib/s3-api.ts"
import { defineApi } from "@dimah-s3/react";

export const api = defineApi({
  async upload(payload) {
    /* see Upload */
  },
  async confirm(payload) {
    /* see Upload */
  },
  async download(payload) {
    /* see Download */
  },
  async catalog() {
    /* return route capabilities and upload constraints */
  },
  async delete(payload) {
    /* see Delete */
  },
  async deleteMany(payload) {
    /* delete each requested key and return one result per key */
  },
  multipart: {
    async init(payload) {
      /* see Multipart */
    },
    async signPart(payload) {
      /* see Multipart */
    },
    async listParts(payload) {
      /* see Multipart */
    },
    async complete(payload) {
      /* see Multipart */
    },
    async abort(payload) {
      /* see Multipart */
    },
  },
});
```

`catalog` is required because upload hooks use it to discover route
capabilities, accepted file types, maximum size, and multipart policy.
`deleteMany` is required by batch deletion and returns an independent result
for every key (up to 100). The remaining methods are required by their
corresponding upload, download, delete, and multipart hooks; response shapes
must match the [core `S3Api` protocol](https://v1.s3.dimah.dev/docs/core).
