Documentation
Docs
Introduction
Getting Started
Tutorial: build an app
Core Concepts
Routing
Server-Side Rendering
Mimir, state management
Pages & Layouts
API Routes
Styling & Theming
Building & Deploying
API Reference
Guides
Recipes
FAQ (use cases)
Tutorial , 6. API routes
So far notes live only in the browser, a reload (without the session) loses new ones, and they are not shared. Let us add a tiny API in the same app to persist notes server-side, then have the client read and write through it.
A server-side store
For the tutorial, keep notes in a JSON file (the runtime's ekko:fs writes it, you granted fs):
Granting
fslets the app read and write files. Scope it in production (fs: ["./data/**", ...]) so the app can only touch what it needs, see Permissions.
The API routes
Register them on the same app. Handlers get (req, res); returning a value auto-sends it (objects as
JSON):
req gives you params (from :id), query (the raw query string, parse as needed), body (the raw
request body string, call await req.json() to parse it), and user (if middleware set it). res has json,
send, status, and header. See Request & response.
The client uses the API
Replace the local-only writes with fetches. Load the notes into the atom on mount, and POST on save:
The server persists to data/notes.json, invalidates the cached list page, and the next render shows the new
note, to every visitor, surviving restarts.
405 for free
When you declare GET and POST on /api/notes, rune automatically answers other methods (PUT/DELETE/...)
to that path with 405 Method Not Allowed and an allowed list. You do not write that handler. See
Validation & options.
One app, no second server
The key point: the API and the pages are the same process. allNotes() is a function call, not an HTTP
hop; the API and the SSR render read the same data; and you invalidate the page cache from the API handler
directly. No CORS, no separate deploy, no type boundary.
Next: a proper theme and polish, 7. Styling.