# Integration (https://form.dimah.dev/docs/integration)



`@dimah-form/server` creates one instance with an HTTP `handler` and an
in-process `api`. Persistence is required; SQL is not.

```ts title="lib/form.ts"
import { dimahForm, memoryAdapter } from "@dimah-form/server";
import { forms } from "@/lib/forms";

export const form = dimahForm({
  database: memoryAdapter(),
  forms,
  basePath: "/api/form",
});

export type Form = typeof form;
```

`basePath` must match `createFormClient()`. Use `memoryAdapter()` for tests and
local development; choose SQL or a custom `ResponseStore` in
[Persistence](https://form.dimah.dev/docs/persistence.md).

## Mount the handler [#mount-the-handler]

```ts title="app/api/form/[...all]/route.ts"
import { toNextJsHandler } from "@dimah-form/server/next";
import { form } from "@/lib/form";

export const { GET, POST, PUT, PATCH, DELETE } = toNextJsHandler(form);
```

Supported adapters are `next`, `node`, `express`, `hono`, `fastify`, `elysia`,
and `svelte-kit`. Each receives the same `form` instance:

| Runtime   | Import                                                 |
| --------- | ------------------------------------------------------ |
| Express   | `@dimah-form/server/express` → `toExpressHandler`      |
| Hono      | `@dimah-form/server/hono` → `toHonoHandler`            |
| Fastify   | `@dimah-form/server/fastify` → `toFastifyHandler`      |
| Elysia    | `@dimah-form/server/elysia` → `toElysiaHandler`        |
| SvelteKit | `@dimah-form/server/svelte-kit` → `toSvelteKitHandler` |
| Node.js   | `@dimah-form/server/node` → `toNodeHandler`            |

<Callout type="warn">
  Express and Fastify must pass an unread request body to the adapter. Mount the
  dimah-form route before `express.json()` or configure Fastify so its JSON
  parser does not consume `/api/form/*` first.
</Callout>

<Tabs items="[&#x22;Express&#x22;, &#x22;Hono&#x22;, &#x22;SvelteKit&#x22;, &#x22;Node.js&#x22;]">
  <Tab value="Express">
    ```ts
    import express from "express";
    import { toExpressHandler } from "@dimah-form/server/express";

    const app = express();
    app.all("/api/form/*", toExpressHandler(form));
    app.use(express.json());
    ```
  </Tab>

  <Tab value="Hono">
    ```ts
    import { Hono } from "hono";
    import { toHonoHandler } from "@dimah-form/server/hono";

    const app = new Hono();
    app.on(
      ["GET", "POST", "PUT", "PATCH", "DELETE"],
      "/api/form/*",
      toHonoHandler(form),
    );
    ```
  </Tab>

  <Tab value="SvelteKit">
    ```ts title="src/routes/api/form/[...path]/+server.ts"
    import { toSvelteKitHandler } from "@dimah-form/server/svelte-kit";
    import { form } from "$lib/form";

    const handler = toSvelteKitHandler(form);
    export const GET = handler;
    export const POST = handler;
    export const PUT = handler;
    export const PATCH = handler;
    export const DELETE = handler;
    ```
  </Tab>

  <Tab value="Node.js">
    ```ts
    import { createServer } from "node:http";
    import { toNodeHandler } from "@dimah-form/server/node";

    createServer(toNodeHandler(form)).listen(3000);
    ```
  </Tab>
</Tabs>

For an edge or Fetch runtime, forward the request directly:

```ts
export default {
  fetch(request: Request) {
    return form.handler(request);
  },
};
```

## Call in process [#call-in-process]

`form.api` exposes the same operations as HTTP without a loopback request.
Forward request headers when `guard` needs the caller's session.

```tsx title="app/survey/[slug]/page.tsx"
import { headers } from "next/headers";
import { notFound } from "next/navigation";
import { isFormErrorCode } from "@dimah-form/server";
import { Questionnaire } from "@/components/questionnaire";
import { form } from "@/lib/form";

export default async function SurveyPage({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;

  try {
    const snapshot = await form.api.getForm({
      query: { formId: slug },
      headers: await headers(),
    });
    return <Questionnaire form={snapshot} />;
  } catch (error) {
    if (isFormErrorCode(error, "UNKNOWN_FORM")) notFound();
    throw error;
  }
}
```

Route paths and request payloads are documented in [Protocol](https://form.dimah.dev/docs/protocol.md).
Put authorization and side effects in [Security](https://form.dimah.dev/docs/security.md), not in an
adapter.

## Next [#next]

<Cards>
  <Card title="Persistence" href="/docs/persistence" description="Choose memory, SQL, or a custom store." />

  <Card title="Security" href="/docs/security" description="Authorize operations and stamp response ownership." />
</Cards>
