Skip to content

Server-Side Architecture

API keys for OpenAI, Anthropic, and Google must never be in browser bundles. IntentForm provides three server-side patterns depending on your stack.

Pattern 0 — Client-side only (demos only)

Section titled “Pattern 0 — Client-side only (demos only)”
flowchart LR
  B[Browser] -->|direct API call| AI[(AI provider)]
  style B fill:#313244,stroke:#f38ba8,color:#cdd6f4
  style AI fill:#313244,stroke:#cba6f7,color:#cdd6f4

The provider is instantiated in the browser with the API key passed directly. Only acceptable for local dev or playgrounds where the key is disposable.

// ONLY for demos — key exposed in browser
const engine = createIntentForm({
provider: openaiProvider({ apiKey: import.meta.env.VITE_OPENAI_API_KEY }),
models: [...],
})

Pattern A — Node.js backend (@intentform/server)

Section titled “Pattern A — Node.js backend (@intentform/server)”

The engine runs on your server. The browser uses @intentform/client to POST a prompt string to your endpoint. API key never leaves the server.

flowchart LR
  B[Browser] -->|POST /api/intent| S["@intentform/server\nNode.js handler"]
  S --> E["engine.parse()"]
  E --> AI[(AI provider)]
  AI --> R["IntentResolution\nJSON response"]
  R --> B
  style B fill:#313244,stroke:#89dceb,color:#cdd6f4
  style S fill:#313244,stroke:#cba6f7,color:#cdd6f4
  style E fill:#313244,stroke:#b4befe,color:#cdd6f4
  style AI fill:#313244,stroke:#a6e3a1,color:#cdd6f4
  style R fill:#313244,stroke:#fab387,color:#cdd6f4

Supported server frameworks:

FrameworkHelperRecipe
HonocreateIntentFormHonoRoute(engine)Hono recipe
Next.js App RoutercreateIntentFormNextHandler(engine)Next.js recipe
TanStack StartcreateIntentFormServerFn(engine)TanStack Start recipe
Generic Web FetchcreateIntentFormRoute(engine)see below

Generic handler (Cloudflare Workers, Bun.serve, Deno.serve, etc.):

import { createIntentFormRoute } from '@intentform/server'
const handler = createIntentFormRoute(engine)
export default { fetch: handler }

Browser client:

import { createClientIntentForm } from '@intentform/client'
const engine = createClientIntentForm({
endpoint: '/api/intent',
models: myModels, // needed client-side for field rendering only
})

Pattern B — Non-Node backend (@intentform/server-http)

Section titled “Pattern B — Non-Node backend (@intentform/server-http)”

If your backend is Spring Boot, .NET, Django, or any other non-Node runtime, run @intentform/server-http as a sidecar container. Your backend doesn’t need to know about AI at all.

flowchart LR
  B[Browser] -->|POST /api/intent| SC["@intentform/server-http\nDocker sidecar"]
  SC --> AI[(AI provider)]
  AI --> R["JSON response"]
  R --> B
  style B fill:#313244,stroke:#89dceb,color:#cdd6f4
  style SC fill:#313244,stroke:#f38ba8,color:#cdd6f4
  style AI fill:#313244,stroke:#a6e3a1,color:#cdd6f4
  style R fill:#313244,stroke:#fab387,color:#cdd6f4

See the HTTP Sidecar recipe for Docker Compose setup, env vars, and backend integration examples.

SituationPattern
Local dev / playground0 (client-side)
Node.js backend (Hono, Next, TanStack Start)A (@intentform/server)
Serverless / edge (Cloudflare, Vercel Edge)A (generic Web Fetch handler)
Non-Node backend (Spring, .NET, Python)B (@intentform/server-http sidecar)

When Pattern A or B is exposed to the browser, protect the endpoint:

  • Auth: set INTENTFORM_AUTH_TOKEN (sidecar) or validate a bearer token in your Node handler before calling the engine.
  • CORS: set INTENTFORM_CORS_ORIGIN (sidecar) or configure CORS middleware in your Node framework.