GETTING STARTED

Quick Start

This walks through the smallest complete Futon app — a handful of routes, some middleware, and a Node runtime adapter to actually serve requests.

1. Build the App

app.ts
import { Futon, json, logger, cors } from '@rasenganjs/futon'; export const app = new Futon(); app.use(logger()); app.use(cors()); app.get('/', async () => json({ message: 'Hello from Futon!' })); app.get('/users/:id', async (ctx) => { const { id } = ctx.params; return json({ id }); }); app.notFound(async () => json({ error: 'Not Found' }, { status: 404 })); app.onError(async (error, ctx) => { console.error(error); return json({ error: error.message }, { status: 500 }); });

2. Serve It with the Node Adapter

Futon doesn't bind a port itself — that's the runtime adapter's job. For Node:

index.ts
import { NodeDevAdapter } from '@rasenganjs/runtime/adapters/node'; import { app } from './app.js'; const adapter = new NodeDevAdapter({ port: 3000 }); await adapter.serve(app);

Run it with tsx or plain Node (with a build step):

Terminal
npx tsx index.ts # Server listening on http://localhost:3000

3. Try It Out

Terminal
curl http://localhost:3000/ # {"message":"Hello from Futon!"} curl http://localhost:3000/users/42 # {"id":"42"}

What Just Happened

  1. app.use(logger()) and app.use(cors()) registered global middleware, run for every request in the order they were added.
  2. app.get("/users/:id", ...) registered a route:id is a named path parameter, available on ctx.params.
  3. app.notFound() and app.onError() gave Futon fallback handlers for unmatched routes and uncaught exceptions.
  4. NodeDevAdapter took the Futon instance and turned it into an actual listening HTTP server.

Next Steps

Installation
Router