Fetch to make HTTP requests back to your API routes. Client actions like SetState and ShowToast run instantly in the browser — Fetch handles the server round-trips.
Prefab has no dependency on any web framework. This guide uses FastAPI, but the pattern works with anything that can serve HTML and JSON — Flask, Django, Starlette, or even a plain socket server.
Quick Start
A Prefab + FastAPI app has three kinds of routes:- Page routes return HTML — they build a component tree, wrap it in
PrefabApp, and call.html() - Data routes return plain JSON (lists, dicts) — consumed via
result_keyinto state - Component routes return a component tree as JSON (via
.to_json()) — rendered by aSlot
uvicorn app:app --reload and visit http://localhost:8000. Typing in the search box fires a GET /api/items?q=... request on every keystroke, and the results re-render automatically.
PrefabApp.html() returns a self-contained HTML page with the renderer, component tree, and initial state baked in — no external assets or build step needed. The title parameter sets the browser tab title.
When an Input has
on_change, you must include SetState to update the input’s value — the auto-sync is replaced by your custom handler. Use {{ $event }} to reference the current input value.Patterns
Loading Data
Fetch.get makes a GET request and writes the parsed JSON response into client-side state via result_key. Components that reference that key re-render automatically.
params — values support expression interpolation:
Submitting Data
Fetch.post sends a JSON body to your API. Wrap inputs in a Form so that pressing Enter triggers submission.
Reference named inputs by assigning the component to a variable and using .rx, or create an Rx reference directly — make sure each key is initialized in your PrefabApp(state=...), otherwise unset values render as literal template strings.
Forms in Dialogs
For forms that shouldn’t clutter the main layout, put them inside aDialog. Use CloseOverlay() in the success chain to dismiss the dialog after submission:
Dialog is the trigger element (the ”+ Add” button). Everything after it becomes the dialog’s body.
Deleting Data
Fetch.delete sends a DELETE request. Chain a Fetch.get in on_success to refresh the list after removal:
Dynamic Component Routes
Data routes return plain values that templates interpolate. But sometimes you want the server to return entire UI fragments — a detail panel, a chart, a custom card layout. That’s what component routes are for. A component route builds a component tree in Python and returns its JSON representation. On the client, aSlot renders whatever component tree lands in its state key:
Slot shows its fallback children until a Fetch writes a component tree into the detail state key. This is the same pattern that CallTool uses in FastMCP — the server decides what to render, not just what data to return.
Error Handling
Non-2xx responses triggeron_error. The $error variable contains the status line (e.g., “400 Bad Request”), which you can surface with a toast or write to state for inline display:
HTTPException to return error status codes:
Loading States
Action chains execute sequentially and short-circuit on failure. Wrap aFetch with SetState calls to show and hide a loading indicator:
SetState("saving", False) never runs. Handle cleanup in on_error if needed.
Refreshing After Mutations
After a successful POST or DELETE, you often want to reload the data list. Chain aFetch.get inside on_success:
FastMCP vs API Server
Both use the same components and state model. The difference is how the UI talks to your server:| FastMCP | API Server | |
|---|---|---|
| Transport | MCP protocol | HTTP (fetch) |
| Server action | CallTool | Fetch |
| Hosting | Inside Claude Desktop, ChatGPT, etc. | Standalone web page |
| Renderer | Provided by the MCP host | Bundled in PrefabApp.html() |
CallTool. If you’re building a web app, use Fetch. The component tree and client-side actions are identical either way.
Example App
Theexamples/hitchhikers-guide directory contains a complete working app — a Hitchhiker’s Guide catalog with live search, dialog-based entry creation, inline deletion, and error handling. The same directory also contains a FastMCP version of the same app for comparison.